• 跨域


    本文主要涉及三种跨域方法:JSONP、CORS、postMessage。

    Q:为什么会出现跨域问题?  
    A:出于浏览器的同源策略限制,浏览器会拒绝跨域请求。 *注:严格的说,浏览器并不是拒绝所有的跨域请求,实际上拒绝的是跨域的读操作。浏览器的同源限制策略是这样执行的: 通常浏览器允许进行跨域写操作(Cross-origin writes),如链接,重定向; 通常浏览器允许跨域资源嵌入(Cross-origin embedding),如 img、script 标签; 通常浏览器不允许跨域读操作(Cross-origin reads)。* Q:什么情况才算作跨域?
    A:非同源请求,均为跨域。名词解释:同源 —— 如果两个页面拥有相同的协议(protocol),端口(port)和主机(host),那么这两个页面就属于同一个源(origin)。 Q:为什么有跨域需求
    ? A:场景 —— 工程服务化后,不同职责的服务分散在不同的工程中,往往这些工程的域名是不同的,但一个需求可能需要对应到多个服务,这时便需要调用不同服务的接口,因此会出现跨域。

    如何实现跨域

    通常,最常用的跨域方式有以下三种:JSONP、CORS、postMessage。

    JSONP

    单纯地为了实现跨域请求而创造的一个 trick。
    【实现原理】
    虽然因为同源策略的影响,不能通过XMLHttpRequest请求不同域上的数据(Cross-origin reads)。但是,在页面上引入不同域上的js脚本文件却是可以的(Cross-origin embedding)。因此在js文件载入完毕之后,触发回调,可以将需要的data作为参数传入。
    【实现方式(需前后端配合)】

    <script type="text/javascript">
        function dosomething(data){
            //处理获得的数据
        }
    </script>
    <script src="http://example.com/data.php?callback=dosomething"></script>

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

    CORS

    CORS 是W3C 推荐的一种新的官方方案,能使服务器支持 XMLHttpRequest 的跨域请求。CORS 实现起来非常方便,只需要增加一些 HTTP 头,让服务器能声明允许的访问来源。

    值得注意的是,通常使用CORS时,异步请求会被分为简单请求和非简单请求,非简单请求的区别是会先发一次预检请求。
    【简单请求】
    使用下列方法之一且没有人为设置对 CORS 安全的首部字段集合之外的其他首部字段:

    • GET
    • HEAD
    • POST
    - 仅当POST方法的Content-Type值等于下列之一才算作简单请求
           - text/plain
           - multipart/form-data
           - application/x-www-form-urlencoded

    请求报文:

    GET /resources/public-data/ HTTP/1.1
    Host: bar.other
    User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
    Accept-Language: en-us,en;q=0.5
    Accept-Encoding: gzip,deflate
    Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
    Connection: keep-alive
    Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
    Origin: http://foo.example

    请求报文的第10行:Origin: foo.example 表明该请求来源于 foo.exmaple。
    响应报文:

    HTTP/1.1 200 OK
    Date: Mon, 01 Dec 2008 00:23:53 GMT
    Server: Apache/2.0.61 
    Access-Control-Allow-Origin: *
    Keep-Alive: timeout=2, max=100
    Connection: Keep-Alive
    Transfer-Encoding: chunked
    Content-Type: application/xml
    [XML Data]

    响应报文的第4行:Access-Control-Allow-Origin: * 表明该资源可以被任意外域访问。

    【非简单请求】

    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

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

     1.第一条OPTIONS为预检请求,中同时携带了下面两个首部字段:

    Access-Control-Request-Method: POST
    Access-Control-Request-Headers: X-PINGOTHER
    预检请求的Request中的Access-Control-Request-Method: POST,是告诉服务器,之后的实际请求将使用POST方式。
    Access-Control-Request-Headers 是告诉服务器,实际请求将携带两个自定义请求首部字段:X-PINGOTHER 与 Content-Type。服务器据此决定,该实际请求是否被允许

    预检请求的Response中的

    Access-Control-Allow-Origin: foo.example // 标识可接受的跨域请求源;
    Access-Control-Allow-Methods: POST, GET, OPTIONS //标识可接受的跨域请求方法,如GET、POST、OPTIONS;
    Access-Control-Allow-Headers: X-PINGOTHER, Content-Type //标识可接受的跨域请求自定义头;
    Access-Control-Max-Age: 86400。 //标识本次预请求的有效时间(秒),期间内无需再发送预请求;

    服务端返回的响应头中的 Access-Control-Allow-Credentials 字段存在且为 true 时,浏览器才会将响应结果传递给客户端程序。另外,Access-Control-Allow-Origin 必须指定请求源的域名,否则响应失败。

    HTTP/1.1 200 OK
    Access-Control-Allow-Origin: http://foo.com
    Access-Control-Allow-Credentials: true
    Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT
    Keep-Alive: timeout=2, max=100
    Connection: Keep-Alive
    Content-Type: text/plain

    如下图所示为附带身份凭证的请求流程图:

     

    postMessage

    window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。

    otherWindow.postMessage(message, targetOrigin, [transfer]);
  • 相关阅读:
    实时信号阻塞队列大小测试
    实时信号和非实时信号
    [Linux]关于sigprocmask函数的讨论
    java中Map集合的常用方法 (转)
    佛跳墙
    百万数据查询效率提高方法(转)
    bootstrap table 前后端分页(超级简单)
    bootstrap table 分页序号递增问题 (转)
    Spring boot+mybatis+thymeleaf 实现登录注册,增删改查
    js弹出对话框的三种方式(转)
  • 原文地址:https://www.cnblogs.com/magicg/p/13670412.html
Copyright © 2020-2023  润新知