一.什么是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. Codeforces | CF1037D 【Valid BFS?】

    题目大意:给定一个\(n(1\leq n\leq 2\cdot10^5)\)个节点的树的\(n-1\)条边和这棵树的一个\(BFS\)序\(a_1,a_2,\dots,a_n\),判断这个\(BFS\ ...

  2. 【git】git撤销与回滚

    git的撤销与回滚在平时使用中还是比较多的,比如说我们想将某个修改后的文件撤销到上一个版本,或者是想撤销某次多余的提交,都要用到git的撤销和回滚操作.撤销分两种情况,一个是commit之前,一个是c ...

  3. can 网络管理

    网络管理主要功能: 是用来管理ECU是否在网络里面,不在的话请求加入,也就是ALIVE报文, 要判断是否掉线,以及睡眠状态的转换机制,以及跛行状态判,也即是RING报文. 主要的实现逻辑流程: 从rt ...

  4. 利用mysqldump命令导出为csv格式文件

    解决方法: 先导出为txt文件,其内容是以逗号“,”分隔的,得到txt文件后,再自行处理为.csv或者.xls文件. 参数说明: -t, --no-create-info   Don't write ...

  5. css 蒙层

    蒙层 利用z-index: .mui-backdrop-other { position: fixed; top: 44px; right:; bottom:; left:; z-index:; ba ...

  6. mysql视图和临时表的区别

    视图 视图是由从数据库的基本表中选出来的数据组成的逻辑窗口,它与基本表不同的是,视图是一个虚表.数据库中只存放视图的定义,而不存放视图包含的数据,这些数据仍存放在原来的基表中.所以基表中的数据如果发生 ...

  7. Button中command后面函数添加参数解决方法

    添加按钮,按钮的功效由command=函数名,后面的函数实现,但是如果直接写函数名,碰上那些需要参数的函数就会出错 因此,有个简单方法command=lambda:函数名(参数1,参数2.....) ...

  8. Java 存储时间戳的几种方式

    有时需要记录一下数据生成时间的时间戳,精确到秒,这里记录一下java存储时间戳字符串的几种方式 1.DateFormat private static final SimpleDateFormat s ...

  9. Windows 查看端口占用情况

    今天打算运行一下当年的毕业设计,结果启动ActiveMQ的时候,发现报错 原来是端口占用了.在Windows上怎样看呢? Ctrl+Alt+Del 调出任务管理器 再找到资源监视器 原来是依赖于Erl ...

  10. C++基础知识--DAY4

    今天主要讲的是类中除了构造器析构器以外的拷贝构造器,运算符重载等问题 首先是拷贝构造器 1. copy constructor(拷贝构造) 其也是构造器,其地位和constructor的地位是一样的 ...