目录导航
1.什么是跨域?
(1)简单的来说,跨域就是浏览器内核同源策略对JavaScript代码的一种限制。例如在当前服务器的网站下不可执行另外网站的js代码。
(2)常见的例如:dom和js对象无法获取,ajax请求服务器数据显示:No ‘Access-Control-Allow-Origin’ header is present on the requested resource.错误。
2.同源策略
(1)同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。
(2)浏览器判断同源的标准:
首先分析一下一个url的组成:http://localhost:8080/xxx.html
协议:http https 都是常见的协议
ip:一般本机的ip都是127.0.0.1或localhost来代替。
端口:比如常见的网站端口默认是80,等等。
http://localhost/bbb.html 与 http://localhost/aaa.html 同源 协议 ip 端口都一致
http://localhost/bbb.html 与 https://localhost/aaa.html 跨域 协议不一致
http://localhost/bbb.html 与 http://127.0.0.1/aaa.html 跨域 ip 不一致(浏览器认为localhost和127.0.0.1是属于跨域,很多人会混淆)
http://localhost/xxx.html 与 http://localhost:8080/xxx.html 端口不一致 属于跨域
3.项目场景
(1)前端项目发布服务端口为80,后端服务端口为8081的情况下。这时候前端ajax请求后端服务就属于跨域访问,返回的数据将会被浏览器拦截,从而报错。(Allow-Origin’ header is present on the requested resource)
*4.解决方法(重点)
(1)使用@CrossOrigin注解
(2)使用corsfilter过滤器
整理好的代码片段如下:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
final CorsConfiguration corsConfiguration = new CorsConfiguration();
//是否允许请求带有验证信息
corsConfiguration.setAllowCredentials(true);
corsConfiguration.addAllowedOriginPattern("http://localhost:8081"); //单个域名设置
/*允许服务端访问的客户端请求头*/
corsConfiguration.addAllowedHeader("*");
/*允许访问的方法名,GET POST等*/
corsConfiguration.addAllowedMethod("*");
//注册url路径,/**为全部路径匹配
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
}
(3)全局跨域设置。(推荐)
继承WebMvcConfigurer,通过addCorsMappings方法实现跨域访问。
代码如下:
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 注册路径 //注册所有域名
registry.addMapping("/**").allowedOriginPatterns("*")
//注册可以请求的方法
.allowedMethods("GET", "HEAD", "POST","PUT", "DELETE", "OPTIONS")
.allowCredentials(true).maxAge(3600);
}
}
**(4)nginx反向代理(代理转发)重要
先上配置,如下:配置文件在安装好的nginx路径下的conf文件夹中的nginx.conf文件
events {
worker_connections 1024;
}
http{
server {
listen 8081;
server_name 192.168.1.100;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://192.168.1.100:8082;
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods $http_access_control_request_method;
add_header Access-Control-Allow-Headers $http_access_control_request_headers;
add_header Access-Control-Max-Age 1728000;
add_header Content-Length 300;
return 204;
}
}
}
}
- 首先,配置文件一定要有events{}和http{server{}}。
- 其次,server{}中的listen则是代表我们监听的服务端口。(这里是监听192.168.1.100:8081的服务,然后转发到8082端口)。
- server_name则是服务器的ip或域名。
- 最最最重要的就是location的配置,’/'代表匹配所有192.168.1.100:8081发出的请求。例如:http:192.168.1.100:8081/xx/xxx.js就会被/匹配。
- proxy_set_header:设置转发后的请求头的相关信息
- X-Real-IP :设置真实请求的ip
- REMOTE-HOST:设置真实的请求的真实主机地址
- X-Forwarded-For:第一个ip为客户端请求的ip,第二个则是代理ip(客户端:http://localhost:8081,代理:http://localhost:8082)
- proxy_pass:代理转发url。就是由nginx发送http://localhost:8082,这样nginx和后台就处于同源下,这样就实现跨域访问了。
- 注意: 当proxy_pass的url后面跟上/斜杆时,转发的url有以下情况
假设现在用http://localhost:8081/aaa/xxx.html去访问。
① 当location /aaa/ {
proxy_pass http://localhost:8082
} 代理url:http://localhost:8082/aaa/xxx.html
② 当location /aaa/ {
proxy_pass http://localhost:8082/
} 代理url:http://localhost:8082/xxx.html
由①、②对比,可以知道,当转发的url后面有斜杆时,就会将匹配http://localhost:8081/aaa/变成http://localhost:8082/,如果没有,则只替换前面的协议+ip+端口。
③ 当location /aaa/ {
proxy_pass http://localhost:8082/bbb/
} 代理url:http://localhost:8082/bbb/xxx.html
④ 当location /aaa/ {
proxy_pass http://localhost:8082/bbb
} 代理url:http://localhost:8082/bbbxxx.html
由③、④对比,相同的是,都改变了url,不同的是,有斜杆的③分多了一级,而④是直接拼接。 - add_header:添加响应头信息。(跨域访问,并不是请求不到数据,而是接收不到数据)。所以,我们可以在响应头中添加对应origin值,add_header Access-Control-Allow-Origin $http_origin; 这样浏览器就不会拦截。其他数据类似corsfilter配置的信息,允许cookies、请求方法类型之类的,可自行上网查找。
- $request_method = ‘OPTIONS’:浏览器将cors请求(跨域请求)分为两种。一是简单请求。二是非简单请求。只要同时满足以下两大条件,就属于简单请求。
(1) 请求方法是以下三种方法之一:HEAD、GET、POST
(2)HTTP的头信息不超出以下几种字段:Accept、Accept-Language、ContentLanguage、Last-Event-ID
(3)Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不同时满足上面两个条件,就属于非简单请求。
简单请求浏览器会自动添加一些附加的头信息,而非简单请求浏览器会多出一次附加的请求(options)。options请求会在正式请求前发送,该请求测试接口是否通过,通过才会发送正式请求。你需要确认后台不会拦截该请求,否则你的正式请求将无法被发送。
跨域访问记录。