因同源策略导致的跨域问题在开发过程中经常出现,这里总结了Ajax请求导致的跨域问题解决方法。
其中CORS是最常用也是最全面的解决方案。
前端与后端都可以解决跨域问题,主要有以下四种方法:
CORS
CORS是W3C标准,全称为跨域资源共享(Cross-origin resource sharing)
CORS是跨域问题的终极解决方案,是以官方标准的形式推出的,而其余解决方案其实都是以各种方式避开同源策略的限制。不像是JSONP必须是GET请求,使用CORS时没有任何限制,且个人感觉用起来也比较丝滑。
使用CORS的前提是需要浏览器支持,现在较新的浏览器均支持CORS,若是旧版浏览器则无法使用CORS。所以需要确认用户使用环境是支持CORS的浏览器,在此基础上后端再实现对CORS的支持。
简单请求与非简单请求
CORS请求分为两类:简单请求和非简单请求。
同时满足两个条件,即为简单请求,反之为非简单请求。
- 请求方法是以下方法之一
-
- GET
- POST
- HEAD
- HTTP的头信息不超过以下几个字段
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
两种请求跨域时的处理方式
简单请求
浏览器会直接发送简单请求给服务器,同时在请求头上添加一个Origin字段,Origin字段说明本次请求的源(协议+域名+端口号)。
服务端收到请求后,会根据Origin字段判断是否允许这次跨域请求,若允许,则会在返回的头信息里添加一些字段
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
- Access-Control-Allow-Origin 字段是必有的,浏览器会根据此字段判断请求是否成功,若不包含此字段则意味着此次请求不在跨域允许范围内,浏览器会抛出CORS异常。
- Access-Control-Allow-Credentials表示服务器是否允许发送cookie
- Access-Control-Expose-Headers 表示返回值允许暴露的字段
非简单请求
对于非简单请求,浏览器会先发送一个没有请求体的预检请求,再发送带请求体的正式请求:
预检请求用于询问服务器,当前域名是否在服务器允许范围内,以及可以使用哪些HTTP Header字段。得到肯定回复后再发送正式请求
预检请求的方法是OPTIONS,主要包含三个关键的请求头:
- Origin:说明请求源
- Access-Control-Request-Method:说明之后的正式请求会用到哪个HTTP方法
- Access-Control-Request-Headers:说明CORS请求会额外发送的请求头字段
服务器会返回包含Access-Control-Allow-Origin字段的头信息:
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 1728000
若没有任何CORS相关的头字段信息则表示服务端不同意预检请求,不会进行之后的正式请求
- Access-Control-Allow-Methods
-
- 表示服务器支持的所有跨域请求的方法,不仅仅是这一次预检的方法,这样可以避免多次预检
- Access-Control-Allow-Headers
-
- 表示服务器支持的所有头字段信息
- Access-Control-Allow-Credentials
-
- 与简单请求时一样,表示服务器是否允许发送cookie
- Access-Control-Max-Age
-
- 指定本次预检请求的有效期。即预检结果的缓存时间
服务端/nginx设置
- 服务端如何设置
对于Spring boot后端工程,只需在Controller层添加注解即可:
@CrossOrigin
- 现在大部分后端工程都会通过nginx进行请求转发,也可以在nginx里设置支持CORS,只需在返回头增加上述以Access-Control-Allow开头的几个字段即可。
架设代理服务器
同域名架设代理服务器,代理服务器转发请求。通过这种方式绕开同源策略的限制。
JSONP
因为同源策略不对<script>标签的src属性进行限制,可以通过此标签发送跨域的Get 请求。
WebSocket
WebSocket是一种通信协议。
浏览器对于WebSocket是不受同源策略限制的,只要服务器支持此协议的请求,就可以通过WebSocket进行跨域请求。
主要原因是因为WebSocket协议头信息包含Origin字段,服务器会根据此字段判断域名是否在白名单里,所以浏览器没有对WebSocket协议的请求进行同源策略限制。