关于跨域问题学习

1.什么是跨域问题?

     前台调用后台接口的时候不是同一个域的时候就会存在这个问题。

现象:

和普通不跨域请求的区别,多了一个origin:

2.产生跨域问题的原因?

  • 浏览器的限制。出于安全的考虑,多管闲事
  • 跨域(比如:端口号不一致)
  • 发送的是XHR(XMLHttpRequest)请求(重点原因)

3.解决思路

  • 让浏览器不限制。禁止检测,指定参数(客户端改动)
  • 不发送xhr请求,发送jsonp请求。只能发送get请求
  • 修改服务端代码 加header,或者修改nginx 

 解决办法:

    1.客户端浏览器使用命令行参数命令(手动百度) 没有使用价值

    2. 使用jsonp
  jsonp的实现原理  :  

 jsonp发送请求的时候有个callback参数。相当于构造了一个callback方法,而请求的返回值就是其中的参数

type是不同的 jsonp使用的Type是script浏览器不会校验,xhr请求会校验如下图


  jsonp返回的是script,而xhr返回的是json
 使用jsonp时需要修改后端代码:

/**
 * Created by GAOMINGQIAN on 2018/4/15.
 * 支持jsonp的Advice
 */
@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
    public JsonpAdvice() {
        super("callback");
    }
}

3.filter解决方案(主要cookie问题处理)
   当浏览器发现请求是跨域请求时,会在请求头上增加一个Origin字段,当前跨域主键的域 。在响应头上增加字段

/**
 * Created by GAOMINGQIAN on 2018/4/15.
 * 过滤器
 */
public class CrosFilter implements Filter {
    /**
     *  在doFilter里增加响应头
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response=(HttpServletResponse)servletResponse;
        //增加响应的域  为*时,不能满足带cookie的调用
        HttpServletRequest request=(HttpServletRequest) servletRequest;
        if(!StringUtils.isEmpty(request.getHeader("Origin"))){
            response.addHeader("Access-Control-Allow-Origin",request.getHeader("Origin"));
        }
        //自定义头的跨域访问
        String headers=request.getHeader("Access-Control-Request-Headers");
        if(!StringUtils.isEmpty(headers)){
            response.addHeader("Access-Control-Request-Headers",request.getHeader(headers));
        }
        //增加指定允许的方法
        response.addHeader("Access-Control-Allow-Methods","*");
        //带cookie时得跨域
        response.addHeader("Access-Control-Allow-Credentials","true");
        //缓存预解命令 提高效率
        response.addHeader("Access-Control-Max-Age","3600");
        filterChain.doFilter(servletRequest,response);
    }
}
//注册一个Filter的bean
@Bean
public FilterRegistrationBean registerBean(){
   FilterRegistrationBean bean=new FilterRegistrationBean();
   //让所有请求都拦截
   bean.addUrlPatterns("/*");
   //设置filter实例
   bean.setFilter(new CrosFilter());
   return bean;
}

4.Spring框架中的解决方案

  在controller上加@CrossOrigin注解即可

5.使用nginx配置

服务方配置

server{
   listen 80;
   server_name xx.com


   location /{
      proxy_pass http://localhost:8080/;
      add_header Access-Control-Allow-Methods *;
      add_header Access-Control-Max-Age 3600;
      add_header Access-Control-Allow-Credentials true;
      
      add_header Access-Control-Allow-Origin $http_origin;
      add_header Access-Control-Request-Headers 
      $access_control_Request_headers;
      
      if ($request_method=OPTIONS){
          return 200;
      }
   }
}

或者前端方配置反向代理

server{
     listen 80;
     server_name xx.com
     
      location /{
           proxy_pass http://localhost:8081/;
      }
      
      location /client_server{
            proxy_pass http://localhost:8080/test/;
      }
}

扩展:

简单请求和非简单请求
  简单请求浏览器会先执行后判断。非简单请求会先判断后执行(先发一个预解命令)

工作中比较常见的简单请求方法为:GET  HEAD POST
  请求header里面无自定义的头
  Content-Type为以下几种:
              text/plain
              multipart/form-data
              application/x-www-form-urlencoded

非简单请求方法为: put delete方法的ajax请求
   发送json格式的ajax请求
   带自定义头的ajax请求

  非简单请求会发出一次OPTIONS预检命令

我们可以缓存预解命令提高效率

在返回的头上加   response.addHeader("Access-Control-Max-Age","3600");

猜你喜欢

转载自my.oschina.net/gaomq/blog/1795856