跨域资源共享CORS
详细代码及测试案例见ref。
跨域错误产生的条件
- 必须是浏览器上发出的请求
- 必须是XMLHttpRequest请求
- 跨域: 协议,域名,端口任何一个不同就算跨域
解决思路
从三个产生条件上进行解决
针对浏览器
以chrome为例,增加参数–disable-web-security
针对XMLHttpRequest请求
使用jsonp
Spring 4 中可以通过 AbstractJsonpResponseBodyAdvice 支持 jsonp;
Spring 5 中已经移除了相关支持;针对跨域
服务器返回支持跨域信息
//在class上或service方法上使用@CrossOrigin
1 2 3 4 5
@RestController @CrossOrigin public class TestController { //... }
1 2 3 4 5 6 7 8
@RestController public class Controller { @CrossOrigin @GetMapping("/show") public Banner getBanner() { //... } }
使用反向代理(具体见ref)
使用反向代理,代理非本域名的请求,在外面看来就是同一个系统的请求,自然不用担心跨域问题。
以nginx配置为例,配置非常简单,配置如下: 表示 /bcom 开头的请求都转发到 http://b.com:8080/
1 2 3 4 5 6 7 8 9 10 11 12
server { listen 80; server_name a.com; location / { proxy_pass http://a.com:8080/; } location /bcom/ { proxy_pass http://b.com:8080/; } }
带cookie的跨域请求
默认跨域都是不带cookie或身份认证信息等的。
但我们很多时候需要发送cookie(如会话等),这种情况发送XMLHttpRequest请求的时候,客户端需要设置 withCredentials
为true,然后服务端需要返回支持cookie配置,需要返回 Access-Control-Allow-Credentials : true
和 Access-Control-Allow-Origin : 对应的域名
,注意:此处不能用*,必须是具体的域名。
编写js代码:
|
|
编写java代码,后台使用spring的@CookieValue注解获取cookie值。
|
|
注意,@CrossOrigin(allowedHeaders = { “X-Custom-Header1”, “X-Custom-Header2”, “X-Custom-Header4” })需要配置在方法上,不要配在类上面的 @CrossOrigin 注解上,否则会导致一些问题。
编写js代码,JQ里面增加自定义头有2种方法。headers 和 beforeSend事件 加。
带自定义header的跨域请求
很多时候,我们需要发送自定义的header,这个时候首先先要在服务器配置能接受哪些header。并使用 @RequestHeader 得到头字段。
|
|
总结
本着工匠精神就写细一点,发现东西还是比较多的,本来觉得写4个小时应该就能写完了,结果周末花了快2天才写完,最后总结一下,对工作中用得上的知识点。
- 发生跨域访问的三个条件:浏览器端,跨域,异步。
- 针对异步的解决方法jsonp有很多硬伤,并不推荐。
- 浏览器发送跨域请求之前会区分简单请求还是非简单请求,简单请求是直接请求,请求完再根据响应头信息判断(如果不支持跨域,尽管服务器成功执行返回200,但浏览器还是报错),非简单请求会先发送 OPTIONS咨询命令(如果不支持跨域,返回403禁止访问错误,支持则返回200,但并不一定就代表该请求能发出去,某些情况服务器还需要额外判断)。
- 工作中遇到比较常见的非简单请求就是发送json数据的和带自定义头的。(带cookie的是简单请求)
- 使用Spring的 @CrossOrigin 能很方便的解决跨域访问问题,几乎只需要一行代码。
- 使用反向代理也是比较好的解决方法,公司内部配置也比较简单,反向代理能封装很多细节,增加很多其他特性。
- 学会注解 @RequestHeader 和 @CookieValue 的使用,不要自己去request对象上获取这些信息。
相关问题
jsonp为什么只支持get,不支持post?
jsonp不是使用xhr发送的,是使用动态插入script标签实现的,当前无法指定请求的method,只能是get。调用的地方看着一样,实际上和普通的ajax有2点明显差异:1. 不是使用xhr 2.服务器返回的不是json数据,而是js代码。
spring boot 跨域实现
https://spring.io/guides/gs/rest-service-cors/
spring cloud 跨域实现
https://segmentfault.com/a/1190000017188296 https://cloud.spring.io/spring-cloud-gateway/multi/multi__cors_configuration.html