TODO
- 跨域方案
- CORS模块
- JSONP
- CORS处理流程图
- 示例代码
什么是跨域
浏览器为了安全起见,对于浏览器所发出的请求实施同源策略,拦截网页发起不同源请求的响应。
何为不同源?请求链接协议,域名,端口,任意一个不一样,都判定为不同源。浏览器这里的比较是与当前窗口的链接相比。
跨域是指在浏览器中通过XMLHTTPRequest/fetch API发起跟当前页面链接不同源的请求,视为跨域。
跨域解决方案
CORS (跨域资源共享)
CORS,全称Cross-Origin Resource Sharing [1] ,是一种允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本请求访问的机制,通常由于同域安全策略(the same-origin security policy)浏览器会禁止这种跨域请求。
CORS是如何处理跨域请求?

针对简单请求
- 浏览器在请求头部加上origin字段(值为当前域),然后下发请求
- 服务器接到请求后,需要在响应头部中增加Access-Control-Allow-Origin
- 浏览器接到请求后:
- 如果origin不在Access-Control-Allow-Origin范围内,浏览器会拦截该响应。
- 如果origin在Access-Control-Allow-Origin范围内,其他头部限制字段就会接着生效
- Access-Control-Allow-Credentials值为true时,请求对象才能获取cookie信息,请求参数withCredentials需设置为true。Access-Control-Expose-Headers可以放开获取某些非基本头部参数的信息。(Access-Control-Allow-Credentials和Access-Control-Expose-Headers均由服务器返回)
针对非简单请求
- 针对需要发起的请求,先发出预检请求(请求方法:OPTIONS;头部信息包含Origin,Access-Control-Request-Method,Access-Control-Request-Headers)
- 服务器接到预检请求后,根据服务器配置,返回对应响应,主要在响应头部上,响应头部需包含Access-Control-Allow-Origin,Access-Control-Allow-Methods,Access-Control-Allow-Credentials,Access-Control-Allow-Headers,Access-Control-Max-Age),表示是否支持该域的请求。
- 接着按简单请求处理
无论是简单请求还是非简单请求,浏览器都对服务器下发了请求(简单请求下发的是原始请求,非简单请求下发的是预检请求)。最终js代码能否拿到响应数据,是由服务器返回的头部信息来决定,若头部校验不通过,则直接拦截该请求。
满足下面两个条件即为简单请求,反之为非简单请求
- 请求类型:GET、POST、HEAD
- 不包含自定义头部,这三个除外(Accept、Accept-Language、Content-Type(application/x-www-form-urlencoded、multipart/form-data、text/plain)
涉及的头部
- 请求头部
- Origin: 当前域
- Access-Control-Request-Method:列出CORS 请求用到哪个HTTP方法
- Access-Control-Request-Headers:指定 CORS 请求将要加上什么请求头
- 响应头部
- Access-Control-Allow-Credentials:表示是否允许访问cookie
- Access-Control-Expose-Headers:这个字段是给 XMLHttpRequest 对象赋能,让它可以访问其他扩展的头部
- Access-Control-Allow-Origin:表示支持哪些域请求,*表示支持任意
- Access-Control-Allow-Methods:表示支持哪些请求方法
- Access-Control-Allow-Headers:列出支持CORS请求头部字段
- Access-Control-Max-Age:预检请求的有效期,在此期间,不用发出另外一条预检请求
注意事项
- IE低版本不支持
- 需要服务器配置
JSONP
JSONP(JSON with Padding)实际上是借助了script标签不受同源策略限制的特性,同时script标签加载回来的javascript代码会立即被执行的原理实现的。需要客户端跟服务器一起配合才能使用。
实现原理
- 在js中动态加入一个script标签,src指向对应的请求链接
- 通过设置一个参数告诉服务器返回的js代码中应该回调的函数名
- 服务器接收到请求后,通过参数知道返回的js代码调用的函数名
- 服务器处理完请求后,根据对应的js调用的函数名以及处理结果生成对应的js代码,返回给浏览器
- 浏览器接到返回的js代码后,就会立即执行,达到请求-处理的效果
- 同时发起多个jsonp请求,遵循先返回先执行原则,通过宏任务方式执行
注意事项
- script标签是get请求加载,所以这个方案也支持get请求
- 这种方法,有比较大的安全风险,容易受攻击,应开启https搭配使用
- 由于script标签执行时是全局环境,尽量保证每次回调的函数名称是不一样的,不然有可能会导致后面的回调函数覆盖前面的回调函数
img标签
浏览器对于img标签是不受同源策略限制的,所以通过img标签也能向服务器发起请求。由于是图片标签,只能发起请求,无法处理服务器返回的数据。
这种方案常用于前端监控数据上报。
反向代理
反向代理是指请求下发到同源的服务器上,服务器根据请求的头部/路径转发到另一个域的服务器。这里也需要目标服务器放开请求进入。
这种方案的好处在于,在浏览器端基本不涉及跨域问题,相当于把跨域问题挪到后端解决。
总结
- 对于简单的get请求跨域,使用img标签,JSONP实现,兼容性最佳
- 在不考虑低版本的IE浏览器的情况且需要支持多种类型请求时,使用CORS方案
- 上面两种都无法满足时,使用反向代理