zoukankan      html  css  js  c++  java
  • 解决浏览器跨域限制方案之CORS

    一.什么是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
  • 相关阅读:
    交换机技术
    第七周课后总结
    以太网原理
    test
    NetCore第一步:千里之行 始于环境构筑
    第二十课(一)
    第十九课(三)
    第十九课(二)
    第十九课(一)
    第十八课(三)
  • 原文地址:https://www.cnblogs.com/nuccch/p/7467779.html
Copyright © 2011-2022 走看看