CROS跨域请求处理
1.什么是跨域?
跨域是指从一个域名的网页去请求另一个域名的资源。比如从www.baidu.com 页面去请求 www.google.com 的资源。跨域的严格一点的定义是:只要 协议,域名,端口有任何一个的不同,就被当作是跨域
2.为什么浏览器要限制跨域?
原因就是安全问题:如果一个网页可以随意地访问另外一个网站的资源,那么就有可能在客户完全不知情的情况下出现安全问题。比如下面的操作就有安全问题:
- 用户访问www.mybank.com ,登陆并进行网银操作,这时cookie啥的都生成并存放在浏览器
- 用户突然想起件事,并迷迷糊糊地访问了一个邪恶的网站 www.xiee.com
- 这时该网站就可以在它的页面中,拿到银行的cookie,比如用户名,登陆token等,然后发起对www.mybank.com 的操作。
- 如果这时浏览器不予限制,并且银行也没有做响应的安全处理的话,那么用户的信息有可能就这么泄露了。
3.为什么要跨域?
既然有安全问题,那为什么又要跨域呢? 有时公司内部有多个不同的子域,比如一个是location.company.com ,而应用是放在app.company.com , 这时想从 app.company.com去访问 location.company.com 的资源就属于跨域。
4.实现跨域需要的技术手段。
1.JSONP或者CORS
5.SpringMVC通过CORS实现跨域
5.1定义一个Filter
package cn.ucmed.baseline.d2d.api.filter; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class CorsFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) { // CORS "pre-flight" request response.addHeader("Access-Control-Allow-Origin", "*"); response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); response.setHeader("Access-Control-Allow-Headers", "x-requested-with"); response.addHeader("Access-Control-Max-Age", "1800");//30 min } //This will filter your requests and responses. filterChain.doFilter(request, response); } }
5.2在web.xml中配置这个filter
<filter> <filter-name>allowedAccessFilter</filter-name> <filter-class>cn.ucmed.baseline.d2d.api.filter.CorsFilter</filter-class> </filter> <filter-mapping> <filter-name>allowedAccessFilter</filter-name> <url-pattern>/registeryuyue/*</url-pattern> </filter-mapping>
6.SpringBoot通过CORS实现跨域
package cn.ucmed.otaku; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ImportResource; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; @EnableZuulProxy @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class}) @ImportResource("classpath*:META-INF/spring/dubbo.xml") public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } @Bean public CorsFilter corsFilter() { final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); final CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("*"); config.addAllowedHeader("*"); config.addAllowedMethod("OPTIONS"); config.addAllowedMethod("HEAD"); config.addAllowedMethod("GET"); config.addAllowedMethod("PUT"); config.addAllowedMethod("POST"); config.addAllowedMethod("DELETE"); config.addAllowedMethod("PATCH"); config.addExposedHeader("token"); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }
7.jquery $.ajax()跨域请求获取heads。
ajax通过xhr.getAllResponseHeaders()能得到所有response headers,通过xhr.getResponseHeader('token')能获取到具体的head值,but,ajax跨域的请求getAllResponseHeaders()却怎么也获取不到全部的head值,只能获取到content-type这个head值,在http://stackoverflow.com/questions/15042439/cant-get-custom-http-header-response-from-ajax-getallresponseheaders终于找到了答案。需要在服务器端加 'Access-Control-Expose-Headers: header1,header2,header3'才能获取到header1,header2,header3
$.ajax({ type: "get", url: urlStr, //跨域的域名 data: transmitModel, headers: { notice_str: randomStr, timestamp: timestamp, sign: signStr }, success: function(data, status, xhr) { console.info(xhr.getAllResponseHeaders()); console.info(xhr.getResponseHeader('token')) console.info(data); console.info(status); }, error: function(e) { }, complete: function() { } });
SpringMVC的Filter
public class CorsFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) { // CORS "pre-flight" request response.addHeader("Access-Control-Allow-Origin", "*"); response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); response.setHeader("Access-Control-Allow-Headers", "x-requested-with"); response.addHeader("Access-Control-Max-Age", "1800");//30 min response.addHeader("Access-Control-Expose-Headers", "token"); } //This will filter your requests and responses. filterChain.doFilter(request, response); } }
SpringBoot的bean
@Bean public CorsFilter corsFilter() { final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); final CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("*"); config.addAllowedHeader("*"); config.addAllowedMethod("OPTIONS"); config.addAllowedMethod("HEAD"); config.addAllowedMethod("GET"); config.addAllowedMethod("PUT"); config.addAllowedMethod("POST"); config.addAllowedMethod("DELETE"); config.addAllowedMethod("PATCH"); config.addExposedHeader("token"); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); }
参考:
[1]博客,http://www.ruanyifeng.com/blog/2016/04/cors.html,跨资源共享CROS详解
[2]博客,http://blog.csdn.net/notechsolution/article/details/50394391,跨域与跨域访问
[3]博客,https://www.cnblogs.com/wwlhome/p/5787133.html,$.ajax应用之请求头headers
[4]博客,http://www.qdfuns.com/notes/17001/6df913ad0788f32e6908d70c849b7b8e.html,如何获取跨域请求的自定义response headers