浏览器同源策略

假如我们的网站主站为example.com,但同时存在论坛bbs.example.com等分站,主站和分站之间互相调用接口,就会产生跨域问题。

在浏览器中,只有当两个资源地址的协议、端口、主机全部相同时,才说这两个资源是同源的。跨域请求一个图片、一个脚本是没有问题的,但是跨域发起Ajax(Fetch)请求是不允许的,这是因为Ajax能够使用JavaScript代码读取跨域后的返回结果响应给当前网站,这可能被用于钓鱼网站。

解决跨域问题,主要有CORS响应头、jsonp(已过时)两种方案。

CORS响应头

CORS响应头原理其实很简单,就是在跨域调用时,API接口响应头里增加了Access-Control-Allow-Origin等控制字段,标注了该接口允许被调用的来源地址、请求方法等,浏览器识别到这个标识后,便允许该跨域调用。

具体流程如下:

  1. 浏览器检测到跨域请求,在请求前先发送一个OPTIONS类型的preflight请求
  2. 根据preflight响应内容中的CORS响应头,决定是否允许发起跨域请求
  3. 上一步判断为允许,那么正式发起跨域请求

下面例子是一个跨域preflight请求,我们服务端的CORS响应头设置了允许的源地址、允许的HTTP方法等。

这里要尤其注意的一点是跨域响应头要在所有的跨域请求响应中存在,不只是preflight请求!因此CORS响应头一般在服务端框架的过滤器(还有很多种叫法,比如拦截器、中间件、切面等)中实现。

补充:CORS响应头支持IE8+。

CORS响应头的种类

CORS响应头主要有如下6个可以控制的地方:

CORS响应头 说明
Access-Control-Allow-Origin 允许的跨域来源,支持通配符*
Access-Control-Allow-Credentials 请求是否允许携带Cookie
Access-Control-Allow-Methods 请求允许的方法(用于preflight请求)
Access-Control-Allow-Headers 请求允许的请求头(用于preflight请求)
Access-Control-Expose-Headers 可在响应中列出的响应头
Access-Control-Max-Age preflight请求的缓存时间

注意:Access-Control-Allow-Origin谨慎使用*(即允许全部来源的跨域请求),在测试环境中这样设置无可厚非,但生产环境中还是建议白名单方式指定站点。

服务端配置CORS响应头

大多数现代的后端框架都对跨域请求做了统一支持,比如SpringBoot中,我们可以直接使用@CrossOrigin注解标注控制器或方法,允许单组或单个接口跨域请求,也可以统一配置,允许整个工程的接口跨域请求,这里就不多介绍了。

jsonp(已过时)

虽然给服务器设置CORS响应头非常简单,但是如果为了兼容IE考虑,还是需要用jsonp的形式实现跨域Ajax请求。jsonp的原理也比较简单,下面举一个例子。

假设服务器jsonp接口的请求URL为http://xxx/api?callback=showData,我们发起Ajax请求的过程是这样的:

  1. 给页面上添加一个<script src="http://xxx/api?callback=showData"></script>,浏览器就会按照这个地址以JavaScript代码形式加载内容
  2. 服务器返回字符串格式为showData(真正的json数据)
  3. 我们在页面JavaScript代码里预先编写了一个函数showData(result),result参数其实就是真正需要的json数据,这个函数就会恰好被服务端返回的showData(真正的json数据)调用,至此我们就跨域得到了真正的json数据

jsonp的缺点:

  1. 难以控制跨域来源,非常不安全
  2. 过于取巧的实现方式,和利用系统漏洞差不多

随着时代发展,如今IE浏览器已经正式淘汰,因此jsonp方式也已经逐渐消失了。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap