后端接口和前端分离的时候,很多情况下会遇到跨域问题。这是浏览器的同源策略导致的,同源策略是为了Web安全提出的,说的是两个不同源的网址默认是不能请求对方的接口的。不同源包含:协议(http|https)、ip/域名、端口之一不同就是不同源。不同源的网页请求接口都要遵循浏览器的同源策略。
解决跨域问题有两种方案,都需要服务端支持才可以。
一种是JSONP,基本意思是通过在网页上动态添加一个script标签,在这个标签中去请求接口,带上一个函数名,在网页存在,这个是不用遵循同源策略的,这个接口返回中用函数名包裹,页面就可以回调此函数得到真正的数据。JSONP只支持GET方法。
另外一种是CORS(Cross Origin Resource Share),跨域资源共享。这是跨域问题的终极解决方案。支持所有的方法。CORS对于简单请求和非简单请求采取不同的处理方案。简单请求是满足以下条件的请求,不满足的都是非简单请求。
(1) 请求方法是以下三种方法之一:
HEAD
GET
POST
(2)HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin
字段。
下面是一个例子,浏览器发现这次跨源AJAX请求是简单请求,就自动在头信息之中,添加一个Origin
字段。
GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
上面的头信息中,Origin
字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。如果Origin
指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin
字段,就知道出错了,从而抛出一个错误,被XMLHttpRequest
的onerror
回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。
如果Origin
指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
对于非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest
请求,否则就报错。
下面针对Nginx和Java代码作出服务端的CORS配置:
Nginx:
if ( $request_method = 'OPTIONS' ) {
add_header Access-Control-Allow-Origin 'http://somedomain:port';
add_header Access-Control-Allow-Origin '$http_origin';
add_header Access-Control-Allow-Methods 'POST,GET,PUT,OPTIONS,DELETE';
add_header Access-Control-Max-Age 3600;
add_header Access-Control-Allow-Headers 'Origin,X-Requested-With,Content-Type,Accept,Authorization,sourcetype,token';
add_header Access-Control-Allow-Credentials true;
add_header Content-Length 0;
add_header Content-Type text/plain;
return 200;
}
add_header Access-Control-Allow-Origin 'http://somedomain:port';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, PUT, POST, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type,*';
add_header Access-Control-Allow-Origin '$http_origin';//这样就能全部了,*是不行的
静态资源设置允许跨域,否则canvas使用不行
img.crossOrigin = 'anonymous'; //可选值:anonymous,*
服务端nginx
server {
listen 80;
add_header 'Access-Control-Allow-Origin' '*';
location /Roboto/ {
root /home/images;
autoindex on;
}
}
在SpringBoot中可以通过设置Filter或者WebMvcConfigurerAdapter#addCorsMappings(CorsRegistry registry)做配置
先定义CORS每个配置项
@ConfigurationProperties(prefix = "cors")
public class CorsProperties {
private String[] allowedOrigins;
private String[] allowedMethods;
private String[] allowedHeaders;
private String[] exposedHeaders;
private long maxAge;
private boolean allowCredentials;
public String[] getAllowedOrigins() {
return allowedOrigins;
}
public void setAllowedOrigins(String[] allowedOrigins) {
this.allowedOrigins = allowedOrigins;
}
public String[] getAllowedMethods() {
return allowedMethods;
}
public void setAllowedMethods(String[] allowedMethods) {
this.allowedMethods = allowedMethods;
}
public String[] getAllowedHeaders() {
return allowedHeaders;
}
public void setAllowedHeaders(String[] allowedHeaders) {
this.allowedHeaders = allowedHeaders;
}
public String[] getExposedHeaders() {
return exposedHeaders;
}
public void setExposedHeaders(String[] exposedHeaders) {
this.exposedHeaders = exposedHeaders;
}
public long getMaxAge() {
return maxAge;
}
public void setMaxAge(long maxAge) {
this.maxAge = maxAge;
}
public boolean isAllowCredentials() {
return allowCredentials;
}
public void setAllowCredentials(boolean allowCredentials) {
this.allowCredentials = allowCredentials;
}
}
配置文件配置:
#cors.allowedOrigins=http://113.204.233.35:21128
cors.allowedOrigins=*
cors.allowedMethods=POST,GET,PUT,DELETE,OPTIONS,HEAD
#cors.allowedHeaders=Origin,X-Requested-With,Content-Type,Accept,Authorization,token,userId,userCode,userName,user
cors.allowedHeaders=*
cors.maxAge=3600
cors.allowCredentials=true
通过CorsFilter配置:
@Configuration
public class CorsConfig {
@Autowired
private CorsProperties corsProperties;
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig());
return new CorsFilter(source);
}
//基于Spring5的reactive模式的使用CorsWebFilter
@Bean
public CorsWebFilter corsWebFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig());
return new CorsWebFilter(source);
}
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
for (String origin : corsProperties.getAllowedOrigins()) {
corsConfiguration.addAllowedOrigin(origin);
}
for (String method : corsProperties.getAllowedMethods()) {
corsConfiguration.addAllowedMethod(method);
}
for (String header : corsProperties.getAllowedHeaders()) {
corsConfiguration.addAllowedHeader(header);
}
if(ArrayUtil.isNotEmpty(corsProperties.getExposedHeaders())){
for (String header : corsProperties.getExposedHeaders()) {
corsConfiguration.addExposedHeader(header);
}
}
corsConfiguration.setMaxAge(corsProperties.getMaxAge());
corsConfiguration.setAllowCredentials(corsProperties.isAllowCredentials());
return corsConfiguration;
}
}
使用jersey的情况下参考:
https://blog.csdn.net/u013379553/article/details/82725661
参考文件:
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
http://www.ruanyifeng.com/blog/2016/04/cors.html
https://blog.csdn.net/w1316022737/article/details/100010505
https://blog.csdn.net/weixin_36276193/article/details/83870241?depth_1.utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
https://blog.csdn.net/bingospunky/article/details/80136164?depth_1.utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
https://blog.csdn.net/zhengshengnan123/article/details/90400255?depth_1.utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
https://blog.csdn.net/u012988901/article/details/97395556?depth_1.utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task