一.什么是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

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

### 使用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
}

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

}


Filter配置:
```xml
<filter>
<filter-name>CROSFilter</filter-name>
<filter-class>org.chench.springdemo.filter.CROSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CROSFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

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

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

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

【参考】
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. 线性基求第k小异或值

    题目链接 题意:给由 n 个数组成的一个可重集 S,每次给定一个数 k,求一个集合 \(T \subseteq S\), 使得集合 T 在 S 的所有非空子集的不同的异或和中, 其异或和 \(T_1 ...

  2. 【CF429E】Points and Segments(欧拉回路)

    [CF429E]Points and Segments(欧拉回路) 题面 CF 洛谷 题解 欧拉回路有这样一个性质,如果把所有点在平面内排成一行,路径看成区间的覆盖,那么每个点被从左往右的覆盖次数等于 ...

  3. bzoj4540 序列 (单调栈+莫队+rmq)

    首先,如果我知道[l,r],要转移到[l,r+1]的时候,就是加上以r+1为右端点,[l,r+1]为左端点的区间的最小值,其他情况和这个类似 考虑这玩意怎么求 右端点固定的话,我左端点越往左走,这个最 ...

  4. Spring -- <mvc:annotation-driven />

    <mvc:annotation-driven /> 会自动注册:RequestMappingHandlerMapping .RequestMappingHandlerAdapter 与Ex ...

  5. A1144. The Missing Number

    Given N integers, you are supposed to find the smallest positive integer that is NOT in the given li ...

  6. A1120. Friend Numbers

    Two integers are called "friend numbers" if they share the same sum of their digits, and t ...

  7. Ubuntu寻找某某库

    感觉这个方法很有用,记录一下 ubuntu14.04的error while loading shared libraries: libz.so.1问题 我们怎么这知道 libz.so.1在哪个包? ...

  8. 马士兵2string buffuer

    string不可变的字符序列 s1=s1+s2

  9. Mac下如何生成SSH Key-使用GitLab

    步骤1.检查是否已经存在SSH Key 打开电脑终端,输入以下命令: ls -al ~/.ssh 会出现两种情况 步骤2. 生成/设置SSH Key 继续上一步可能出现的情况 (1)情况一:终端出现文 ...

  10. 解决docker多开mysql报错问题

    1.vim /etc/sysctl.conf fs.aio-max-nr=262144 重新加载 sysctl -p /etc/sysctl.conf