什么是跨域请求以及实现跨域的方案

前言:对于跨域请求,很早之前就有去了解过,但因为一直关注的都是服务器后端开发,故也就仅仅停留在概念的理解上而没有机会在实际开发场景中接触得到。最近在公司的开发任务中,需要接触到 Ajax 跨域请求,由于之前没有遇到过类似的问题,在开发过程中遇到不少困难,也查阅了不少资料和博客。在这过程中收获了不少,故特意写下以下文章总结,如果文章有什么不足之处,还望各位指出。

什么是跨域请求

概述

​ 在 HTML 中,,

, ,

然后,我们就可以借助

这时服务端在返回数据的时候,就会返回一端 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 参数的值指定了允许访问该资源的外域 URI。对于不需要携带身份凭证的请求,服务器可以指定该字段的值为通配符,表示允许来自所有域的请求。

  • Access-Control-Allow-Methods

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

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

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

    Access-Control-Allow-Headers: [, ]*
    
  • Access-Control-Max-Age

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

    Access-Control-Max-Age: 
    
  • 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: 
    
  • Access-Control-Request-Method

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

    Access-Control-Request-Method: 
    
  • Access-Control-Request-Headers

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

    Access-Control-Request-Headers: [, ]*
    

示例

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

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

Access-Control-Allow-Methods:*

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

什么是跨域请求以及实现跨域的方案_第1张图片
什么是跨域请求以及实现跨域的方案_第2张图片

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

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

Reference

  • Http跨域请求
  • 浅谈CSRF攻击方式
  • 同源策略详解
  • 详解js跨域问题
  • HTTP访问控制(CORS)
  • 跨域资源共享 CORS 详解

你可能感兴趣的:(什么是跨域请求以及实现跨域的方案)