Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

跨域 #50

Open
wind-jyf opened this issue Dec 5, 2020 · 0 comments
Open

跨域 #50

wind-jyf opened this issue Dec 5, 2020 · 0 comments
Labels

Comments

@wind-jyf
Copy link
Owner

wind-jyf commented Dec 5, 2020

跨域

由于浏览器的同源策略限制,浏览器会拒绝跨域请求。严格的说,浏览器并不是拒绝所有的跨域请求,实际上拒绝的是跨域的读操作。

同源:如果两个页面具有相同的协议、域名和端口,那么这两个页面就属于同一个源。

一、跨域资源共享(cors)

与服务器商量好,让服务器允许跨域。

跨域的判定流程

浏览器和服务器的合作判定步骤如下:

  1. 浏览器先根据同源策略对前端页面和后台交互地址做匹配,若同源,则直接发送数据请求若不同源,则发送跨域请求。
  2. 服务器解析程序收到浏览器跨域请求后,根据自身配置返回对应文件头。若未配置过任何允许跨域,则文件头里不包含**Access-Control-Allow-origin**字段,若配置过域名,则返回Access-Control-Allow-origin+ 对应配置规则里的域名的方式
  3. 浏览器根据接受到的http文件头里的Access-Control-Allow-origin字段做匹配,若无该字段,说明不允许跨域;若有该字段,则对字段内容和当前域名做比对,如果同源,则说明可以跨域,浏览器发送该请求;若不同源,则说明该域名不可跨域,不发送请求。

服务端设置如下:

/*
 * 导入包:import javax.servlet.http.HttpServletResponse;
 * 接口参数中定义:HttpServletResponse response
 */

// 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com"); 

// 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会提示
response.setHeader("Access-Control-Allow-Credentials", "true"); 

// 提示OPTIONS预检时,后端需要设置的两个常用自定义头
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");

CORS常用的配置项有以下几个:

  • Access-Control-Allow-Origin(必含) – 允许的域名,只能填通配符或者单域名
  • Access-Control-Allow-Methods(必含) – 这允许跨域请求的http方法(常见有POSTGETOPTIONS
  • Access-Control-Allow-Headers当预请求中包含Access-Control-Request-Headers时必须包含) – 这是对预请求当中Access-Control-Request-Headers的回复,和上面一样是以逗号分隔的列表,可以返回所有支持的头部。
  • Access-Control-Allow-Credentials(可选) – 该项标志着请求当中是否包含cookies信息,只有一个可选值:true(必为小写)。如果不包含cookies,请略去该项,而不是填写false。这一项与XmlHttpRequest2对象当中的withCredentials属性应保持一致,即withCredentials为true时该项也为true;withCredentials为false时,省略该项不写。反之则导致请求失败。
  • Access-Control-Max-Age(可选) – 以秒为单位的缓存时间。预请求的的发送并非免费午餐,允许时应当尽可能缓存。

在通常使用CORS时,异步请求会分为简单请求和非简单请求,非简单请求的区别是会先发一次预检请求

简单请求

使用下列方法之一且没有人为设置对 CORS 安全的首部字段集合之外的其他首部字段:

  • GET

  • HEAD

  • POST

     仅当POST方法的Content-Type值等于下列之一才算作简单请求
           - text/plain
           - multipart/form-data
           - application/x-www-form-urlencoded
    
非简单请求
  1. 使用了下面任一 HTTP 方法:
  • PUT
  • DELETE
  • CONNECT
  • OPTIONS
  • TRACE
  • PATCH
  1. 人为设置了对 CORS 安全的首部字段集合之外的其他首部字段。该集合为:
  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type (but note the additional requirements below)
  • DPR
  • Downlink
  • Save-Data
  • Viewport-Width
  • Width
  1. Content-Type 的值不属于下列之一:
  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

在发生真正请求前会先发送预检请求,如图所示:

img02

二、jsonp

优点:兼容性好(兼容低版本IE)
缺点:1.JSONP只支持GET请求; 2.XMLHttpRequest相对于JSONP有着更好的错误处理机制

  • 首先,因为ajax无法跨域,然后开发者就有所思考
  • 其次,开发者发现, script标签的src属性是可以跨域的
    把跨域服务器写成 调用本地的函数 ,回调数据回来不就好了?
  • json刚好被js支持(object
  • 调用跨域服务器上动态生成的js格式文件(不管是什么类型的地址,最终生成的返回值都是一段js代码
  • 这种获取远程数据的方式看起来非常像ajax,但其实并不一样
    便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP
  • 传递一个callback参数给跨域服务端,然后跨域服务端返回数据时会将这个callback参数作为函数名来包裹住json数据即可。
 <script>
    var script = document.createElement('script');
    script.type = 'text/javascript';

    // 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
    script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
    document.head.appendChild(script);

    // 回调执行函数
    function handleCallback(res) {
        alert(JSON.stringify(res));
    }
 </script>

服务端返回如下(返回时即执行回调函数)

handleCallback({"status": true, "user": "admin"})

三、代理

代理分为反向代理与正向代理。

顾名思义,这两个方向相反。

正向代理

客户端因为种种原因,没有办法直接与目标服务器联系,这个时候,就使用一个代理服务器,客户端通过这个代理服务器与目标服务器联系。

代理对象是客户端,不知道服务端是谁。

作用:

  1. 访问原来不能访问得资源。
  2. 可以做缓存,加快请求速度。
  3. 对客户端访问授权,上网进行认证。
  4. 代理可以记录用户访问记录,对外隐藏用户信息。

反向代理

比如说百度得服务器,有很多,怎么办?

这个时候就使用一个代理服务器,来处理所有的互联往请求,然后将请求转发给内部得服务器,并从内部服务器获取目标资源,再返回给网络上请求连接得客户端。此时代理服务就对外就表现成了一个服务器。

代理对象是服务端,不知道客户端是谁。

作用:

  1. 保护内网安全,防止网络攻击,大型网站,通常将反向代理服务器地址作为公网访问地址
  2. 负载均衡

所以可以使用代理来跨域,比如说,腾讯得某个服务器没有配置跨域,跨域请求失败,这个时候,可以请求我们自己得服务器,然后让服务器转发我们得请求,因为跨域只有浏览器才有,而服务器没有跨域,所以我们让服务器去访问,访问完了之后,把响应返回给我们。

四、postMessage

H5新引进,可以使用它来向其他得window发送消息,无论是否同源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。

otherWindow.postMessage(message, targetOrigin, [transfer]);

1.)a.html:(http://www.domain1.com/a.html)

<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>       
    var iframe = document.getElementById('iframe');
    iframe.onload = function() {
        var data = {
            name: 'aym'
        };
        // 向domain2传送跨域数据
        iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com');
    };

    // 接受domain2返回数据
    window.addEventListener('message', function(e) {
        alert('data from domain2 ---> ' + e.data);
    }, false);
</script>

2.)b.html:(http://www.domain2.com/b.html)

<script>
    // 接收domain1的数据
    window.addEventListener('message', function(e) {
        alert('data from domain1 ---> ' + e.data);

        var data = JSON.parse(e.data);
        if (data) {
            data.number = 16;

            // 处理后再发回domain1
            window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');
        }
    }, false);
</script>
@wind-jyf wind-jyf added the 计网 label Dec 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant