跨域解决方法,jsonp和cors的优劣性

跨域解决方法

虽然在安全层面上同源限制是必要的,但有时同源策略会对我们的合理用途造成影响,为了避免开发的应用受到限制,有多种方式可以绕开同源策略,下面介绍的是经常使用的 JSONP, CORS 方法。

JSONP

原理:

  • JSONP 是一种非官方的跨域数据交互协议
  • JSONP 本质上是利用 <script><img><iframe> 等标签不受同源策略限制,可以从不同域加载并执行资源的特性,来实现数据跨域传输。
  • JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,而数据就是传入回调函数中的JSON数据。
  • JSONP 的理念就是,与服务端约定好一个回调函数名,服务端接收到请求后,将返回一段 Javascript,在这段 Javascript 代码中调用了约定好的回调函数,并且将数据作为参数进行传递。当网页接收到这段 Javascript 代码后,就会执行这个回调函数,这时数据已经成功传输到客户端了。

示例:

首先当前页面中声明有这样的一个函数,它将作为 JSONP 的回调函数处理作为函数参数传入的数据

<script type="text/javascript">
    function dosomething(jsondata){
        //处理获得的json数据
    }
</script>

然后,我们就可以借助 <script><img><iframe> 等标签可以引入不同域资源的特性,将需要发送的请求的路径作为src参数,其中需要注意的是:需要告知服务端回调函数的函数名。

<script src="http://example.com/data.php?callback=dosomething"></script>

这时服务端在返回数据的时候,就会返回一端 Javascript 代码,在 Javascript代码中调用了回调函数,并且需要返回的数据作为回调函数的参数

dosomething(['a','b','c']);

最后页面成功加载了刚才指定路径的资源后,将会执行该 Javascript 代码,dosomething函数将执行,这时一次跨域请求完成。

另外,如果页面引入了 jQuery,那么可以通过它封装的方法很方便的实现JSONP操作了

// Using YQL and JSONP
$.ajax({
    url: "http://query.yahooapis.com/v1/public/yql",
 
    // The name of the callback parameter, as specified by the YQL service
    jsonp: "callback",
 
    // Tell jQuery we're expecting JSONP
    dataType: "jsonp",
 
    // Tell YQL what we want and that we want JSON
    data: {
        q: "select title,abstract,url from search.news where query=\"cat\"",
        format: "json"
    },
 
    // Work with the response
    success: function( response ) {
        console.log( response ); // server response
    }
});

优缺点:

JSONP 的优点是:它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行。

JSONP 的缺点是:它只支持 GET 请求,而不支持 POST 请求等其他类型的 HTTP 请求

CORS

介绍

​ 跨源资源共享 Cross-Origin Resource Sharing(CORS) 是一个新的 W3C 标准,它新增的一组HTTP首部字段,允许服务端其声明哪些源站有权限访问哪些资源。换言之,它允许浏览器向声明了 CORS 的跨域服务器,发出 XMLHttpReuest 请求,从而克服 Ajax 只能同源使用的限制。

​ 另外,规范也要求对于非简单请求,浏览器必须首先使用 OPTION 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求,在服务器确定允许后,才发起实际的HTTP请求。对于简单请求、非简单请求以及预检请求的详细资料可以阅读HTTP访问控制(CORS)

HTTP 协议 Header 简析

下面对 CORS 中新增的 HTTP 首部字段进行简析:

  • Access-Control-Allow-Origin

    响应首部中可以携带这个头部表示服务器允许哪些域可以访问该资源,其语法如下:

    Access-Control-Allow-Origin: <origin> | *
    

    其中,origin 参数的值指定了允许访问该资源的外域 URI。对于不需要携带身份凭证的请求,服务器可以指定该字段的值为通配符,表示允许来自所有域的请求。

  • Access-Control-Allow-Methods

    该首部字段用于预检请求的响应,指明实际请求所允许使用的HTTP方法。其语法如下:

    Access-Control-Allow-Methods: <method>[, <method>]*
    
  • Access-Control-Allow-Headers

    该首部字段用于预检请求的响应。指明了实际请求中允许携带的首部字段。其语法如下:

    Access-Control-Allow-Headers: <field-name>[, <field-name>]*
    
  • Access-Control-Max-Age

    该首部字段用于预检请求的响应,指定了预检请求能够被缓存多久,其语法如下:

    Access-Control-Max-Age: <delta-seconds>
    
  • Access-Control-Allow-Credentials

    该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。其语法如下:

    Access-Control-Allow-Credentials: true
    

    另外,如果要把 Cookie 发送到服务器,除了服务端要带上Access-Control-Allow-Credentials首部字段外,另一方面请求中也要带上withCredentials属性。

    但是需要注意的是:如果需要在 Ajax 中设置和获取 Cookie,那么Access-Control-Allow-Origin首部字段不能设置为* ,必须设置为具体的 origin 源站。详细可阅读文章CORS 跨域 Cookie 的设置与获取

  • Origin

    该首部字段表明预检请求或实际请求的源站。不管是否为跨域请求,Origin字段总是被发送。其语法如下:

    Origin: <origin>
    
  • Access-Control-Request-Method

    该首部字段用于预检请求。其作用是,将实际请求所使用的 HTTP 方法告诉服务器。其语法如下:

    Access-Control-Request-Method: <method>
    
  • Access-Control-Request-Headers

    该首部字段用于预检请求。其作用是,将实际请求所携带的首部字段告诉服务器。其语法如下:

    Access-Control-Request-Headers: <field-name>[, <field-name>]*
    

示例

假设我们在 bbb.cn 域名下,发送一个 Ajax 请求到 aaa.cn 域名,其路径如下:http://aaa.cn/localserver/api/corsTest 。由于同源策略,这样的 Ajax 请求将会被浏览器所拦截,得到下面的信息:

若想能够发送跨域请求,我们只需要在服务器的响应中配置适当的CORS HTTP 首部字段就可以了,例如可以加入以下的首部字段:

Access-Control-Allow-Methods:*

此时,Ajax请求就可以顺利的发送和接收了,对应的请求和响应头部如下:

对于在 Java Web 项目中,如何在 Servlet 或这 Spring MVC 中配置 CORS 可以阅读文章Spring MVC 实现 CORS 跨域

与 JSONP 的比较

  • JSONP 只能实现 GET 请求,而 CORS 支持所有类型的 HTTP 请求
  • 使用 CORS ,开发者可以是使用普通的 XMLHttpRequest 发起请求和获取数据,比起 JSONP 有更好的错误处理
  • 虽然绝大多数现代的浏览器都已经支持 CORS,但是 CORS 的兼容性比不上 JSONP,一些比较老的浏览器只支持 JSONP



作者:ken_ljq
链接:https://www.jianshu.com/p/f880878c1398
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值