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");
转载于:https://my.oschina.net/gaomq/blog/1795856