一.什么是CORS

CORS是解决浏览器跨域限制的W3C标准,详见:https://www.w3.org/TR/cors/。

根据CORS标准的定义,在浏览器中访问跨域资源时,需要做如下实现:

  • 服务端在响应消息头中包含消息头:Access-Control-Allow-Origin,值为服务端允许访问资源的域名称,同时浏览器会根据该值与发起的请求消息头Origin值进行匹配,以确认服务端是否允许访问跨域资源。
  • 浏览器在发送非“简单方法”(GET,HEAD请求被定义为简单方法)之前,会发送一个预检请求(通常是一个OPTIONS请求),浏览器根据响应消息头验证服务端是否允许访问跨域资源,从而决定是否需要发送“实际请求”。
  • 在服务端根据请求消息头Origin值以决定是否允许浏览器访问跨域资源,返回相应的消息头。

具体来说,在实现时通常需要设置如下几个响应消息头:

  1. Access-Control-Allow-Origin:“origin-list” | “null” | “*”,允许访问跨域资源的域名列表,对于预检请求来说,决定是否会发送实际请求。
  2. Access-Control-Allow-Credentials:true | false,表明实际请求中是否可以包含用户凭证信息。
  3. Access-Control-Allow-Methods:“method”,服务端允许访问的实际请求方法名列表。
  4. Access-Control-Allow-Headers:“field-name”,在“实际”请求中可以包含的消息头名称列表。
  5. Access-Control-Max-Age:seconds,预检请求结果缓存时间,单位:秒。在该时间范围内,发送实际请求之前不再会发送预检请求。

特别说明:对于需要跨域传递Cookie的场景,必须设置消息头“Access-Control-Allow-Credentials”为“true”,且此时“Access-Control-Allow-Origin”值只能为某一指定单一域名。

简而言之,CORS标准的核心就是:服务端需要在浏览器的跨域请求响应中包含指定消息头,如下通过代码示例说明。

二.实现CORS

在Serlvet中实现CORS

  1. public class AjaxCorsServlet extends HttpServlet {
  2. private static final long serialVersionUID = 1L;
  3. private static final Logger logger = Logger.getLogger(AjaxCorsServlet.class.getName());
  4. @Override
  5. protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
  6. throws ServletException, IOException {
  7. String origin = req.getHeader("Origin");
  8. String allowMethod = req.getHeader("Access-Control-Request-Method");
  9. String allowHeaders = req.getHeader("Access-Control-Request-Headers");
  10. resp.setHeader("Access-Control-Allow-Origin", origin);// 允许指定域访问跨域资源
  11. resp.setHeader("Access-Control-Allow-Credentials", "true"); // 允许跨域传递Cookie
  12. resp.setHeader("Access-Control-Max-Age", "86400"); // 浏览器缓存预检请求结果时间,单位:秒
  13. resp.setHeader("Access-Control-Allow-Methods", allowMethod);// 允许浏览器发送的实际请求方法名列表
  14. resp.setHeader("Access-Control-Allow-Headers", allowHeaders);// 允许浏览器发送的请求消息头
  15. }
  16. @Override
  17. protected void doGet(HttpServletRequest req, HttpServletResponse resp)
  18. throws ServletException, IOException {
  19. this.doPost(req, resp);
  20. }
  21. @Override
  22. protected void doPost(HttpServletRequest req, HttpServletResponse resp)
  23. throws ServletException, IOException {
  24. logger.info(String.format("ajax cors post do"));
  25. String origin = req.getHeader("Origin");
  26. resp.setHeader("Access-Control-Allow-Origin", origin); // 在实际请求中允许指定域访问跨域资源
  27. resp.setHeader("Access-Control-Allow-Credentials", "true"); // 允许跨域传递Cookie
  28. resp.setHeader("Content-Type", "application/json"); // 服务端响应的数据类型
  29. User user = new User();
  30. user.setName("ajax cors post do");
  31. user.setPwd("******");
  32. resp.getWriter().write(JSON.toJSONString(user));
  33. }
  34. }

### 使用Spring框架
#### 在Spring 4.1.9.RELEASE及以下版本的解决方案
通过自定义Filter实现CORS,如下代码说明:
```java
public class CROSFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// to do something
}

  1. @Override
  2. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  3. throws IOException, ServletException {
  4. HttpServletRequest req = (HttpServletRequest)request;
  5. HttpServletResponse resp = (HttpServletResponse)response;
  6. String origin = req.getHeader("Origin");
  7. resp.setHeader("Access-Control-Allow-Origin", origin); // 允许指定域访问跨域资源
  8. resp.setHeader("Access-Control-Allow-Credentials", "true"); // 允许跨域传递Cookie
  9. if(RequestMethod.OPTIONS.toString().equals(req.getMethod())) {
  10. String allowMethod = req.getHeader("Access-Control-Request-Method");
  11. String allowHeaders = req.getHeader("Access-Control-Request-Headers");
  12. resp.setHeader("Access-Control-Max-Age", "86400"); // 浏览器缓存预检请求结果时间,单位:秒
  13. resp.setHeader("Access-Control-Allow-Methods", allowMethod); // 允许浏览器发送的实际请求方法名列表
  14. resp.setHeader("Access-Control-Allow-Headers", allowHeaders); // 允许浏览器发送的请求消息头
  15. return;
  16. }
  17. chain.doFilter(request, response);
  18. }
  19. @Override
  20. public void destroy() {
  21. // release resouces
  22. }

}


  1. Filter配置:
  2. ```xml
  3. <filter>
  4. <filter-name>CROSFilter</filter-name>
  5. <filter-class>org.chench.springdemo.filter.CROSFilter</filter-class>
  6. </filter>
  7. <filter-mapping>
  8. <filter-name>CROSFilter</filter-name>
  9. <url-pattern>/*</url-pattern>
  10. </filter-mapping>

在Spring 4.2.0.RC1及以上版本的解决方案

从Spring 4.2.0.RC1版本开始,Spring MVC提供了一个解决浏览器跨域限制的注解CrossOrigin,只需要在Controller方法上使用该注解即可。

  1. @RequestMapping(value="/post", method = {RequestMethod.POST})
  2. @ResponseBody
  3. @CrossOrigin(origin="*") // 使用CrossOrigin注解处理浏览器跨域限制问题
  4. public User testAjaxCORSPost(HttpServletRequest req, HttpServletResponse resp,
  5. @RequestBody User user) {
  6. logger.info("ajax post do");
  7. User u = new User();
  8. u.setName("ajaxPost");
  9. u.setPwd("111");
  10. return u;
  11. }

【参考】
https://spring.io/blog/2015/06/08/cors-support-in-spring-framework

解决浏览器跨域限制方案之CORS的更多相关文章

  1. 解决浏览器跨域限制方案之JSONP

    一.什么是JSONP JSONP即:JSON with Padding,是一种解决因浏览器跨域限制不允许访问跨域资源的方法. JSONP是一个非官方的协议,它允许在服务器端返回javascript标签 ...

  2. 解决浏览器跨域限制方案之WebSocket

    WebSocket是在HTML5中引入的浏览器与服务端的通信协议,可以类比HTTP. 可以在支持HTML5的浏览器版本中使用WebSocket进行数据通信,常见的案例是使用WebSocket进行实时数 ...

  3. 配置nginx反向代理服务器,解决浏览器跨域调用接口的限制问题

    配置nginx反向代理服务器,解决浏览器跨域调用接口的限制问题 - 大venn的博客 - CSDN博客https://blog.csdn.net/u011135260/article/details/ ...

  4. node端代理浏览器路由 解决浏览器跨域问题

    var _ = require('lodash'); var request = require("request"); /* @LM 2017-02-16 node端代理浏览器路 ...

  5. c#解决浏览器跨域问题

    1.浏览器为什么不能跨域? 浏览器有一个基本的安全策略--同源策略.为保证用户的信息安全,它对不同源的文档或脚本对当前文档的读写操作做了限制.域名,子域名,端口号或协议不同都属于不同源,当脚本被认为是 ...

  6. nginx解决浏览器跨域问题

    1.跨域问题 浏览器出于安全方面的考虑,只允许与本域下的接口交互.不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源. 例如访问www.test1.com 页面, 返回的文件中需要ajax向 ...

  7. elk 解决浏览器跨域问题

    1.执行命令: docker pull sebp/elk 将镜像pull到本地来: 2.执行命令: docker run -p 5601:5601 -p 9200:9200 -p 5044:5044 ...

  8. 再也不学AJAX了!(三)跨域获取资源 ② - JSONP & CORS

    浏览器的"同源策略"固然保障了互联网世界的数据隐私与数据安全,但是如果当我们需要使用AJAX跨域请求资源时,"同源策略"又会成为开发者的阻碍.在本文中,我们会简 ...

  9. [1.6W字]浏览器跨域请求的原理, 以及解决方法(可以纯前端实现) #flight.Archives011

    Title/ 浏览器跨域(CrossOrigin)请求的原理, 以及解决方案详细指南 #flight.Archives011 序: 最近看到又有一波新的创作活动了, 官方给出的话题中有一个" ...

随机推荐

  1. 登录Linux服务器显示IP和自定义备注

    默认搭建好的Linux服务器,使用Xshell登录的窗口如下所示: 可根据需要执行如上代码,再重新登录服务器,效果如下图所示: 代码片段:echo "export PS1='\u@\[\e[ ...

  2. 使用Putty执行Rsync命令

    背景介绍:公司的文件服务器有多个,一个Master服务器,10个左右的Slave服务器. 当Master服务器中的文件更新之后,Slave服务器中的文件也必须做相对应的同步操作. 公司目前使用的Rsy ...

  3. 【UOJ#311】【UNR #2】积劳成疾(动态规划)

    [UOJ#311][UNR #2]积劳成疾(动态规划) UOJ Solution 考虑最大值分治解决问题.每次枚举最大值所在的位置,强制不能跨过最大值,左右此时不会影响,可以分开考虑. 那么设\(f[ ...

  4. MVC接收列表参数

    ASP.NET  MVC 表单参数如果有列表时要怎么写呢. 虽然很久不用MVC了,但几乎每次遇到一次就要研究一下.然后又忘了. 其实也明白这是未完全弄清楚表单参数的传递形式,如果明白了,就知道MVC为 ...

  5. 常用CSS样式速查

    writing-mode: vertical-lr; -webkit-writing-mode: vertical-lr; -ms-writing-mode: vertical-lr; 作用 CSS ...

  6. 【dfs】p1731 生日蛋糕

    1441:[例题2]生日蛋搞 [题目描述] 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体.设从下往上数第i(1≤i≤M)层蛋糕是半径为Ri, 高 ...

  7. 【dfs】p1451 求细胞数量

    题目描述 一矩形阵列由数字0到9组成,数字1到9代表细胞,细胞的定义为沿细胞数字上下左右若还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数.(1<=m,n<=100)? 输入输出格式## ...

  8. 如何在Windows 10上运行Docker和Kubernetes?

    如何在Windows 10上运行Docker和Kubernetes? 在Windows上学习Docker和Kubernetes,开始的时候会让你觉得无从下手.最起码安装好这些软件都不是一件容易的事情. ...

  9. WIndows下将文件夹映射为磁盘

    subst 盘符 文件夹路径 [/d] 映射 将e:\work映射为z:盘,使用subst z: e:\work 取消映射 取消z盘映射,使用subst z: /d 参考资料:http://mp.we ...

  10. 【洛谷P1483】序列变换

    题目大意:给定一个长度为 N 的序列,有 M 个操作,支持将下标为 x 的倍数的数都加上 y,查询下标为 i 的元素的值. 题解:由于查询操作很少,相对的,修改操作很多.若直接模拟修改操作,即:枚举倍 ...