前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >解决浏览器跨域限制方案之CORS

解决浏览器跨域限制方案之CORS

作者头像
编程随笔
发布2019-09-11 15:58:24
7550
发布2019-09-11 15:58:24
举报
文章被收录于专栏:后端开发随笔后端开发随笔

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

代码语言:javascript
复制
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,如下代码说明:

代码语言:javascript
复制
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配置:

代码语言:javascript
复制
<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方法上使用该注解即可。

代码语言:javascript
复制
@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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-09-02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.什么是CORS
  • 二.实现CORS
    • 在Serlvet中实现CORS
      • 使用Spring框架
        • 在Spring 4.1.9.RELEASE及以下版本的解决方案
        • 在Spring 4.2.0.RC1及以上版本的解决方案
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档