跨域与解决
# 跨域与解决
# 什么是跨域
当我们在一个域中去请求另一个域的资源的时候就会出现跨域,本质是浏览器的同源策略,目的是为了防止网站内的数据被其他网站盗取,只要协议,ip,端口有任何一个与当前域的不一样就会认为是不同的域,从而触发跨域。跨域不是服务端没有接收处理请求,而是响应回来的数据被浏览器拦截了,
# 解决方案
# 代理
通过将对后端服务的资源请求发送到nginx上,再由nginx进行转发到后端服务,并将响应数据返回给浏览器,把浏览器对前端和后端的访问放到了统一个域下,就自然解决了跨域。
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name tosim.top;
location / {
root html/build;
try_files $uri /index.html; # try_files:检查文件; $uri:监测的文件路径; /index.html:文件不存在重定向的新路径
index index.html;
}
location /api/ {
# 把 /api 路径下的请求转发给真正的后端服务器
proxy_pass http://localhost:18080/;
# 把host头传过去,后端服务程序将收到your.domain.name, 否则收到的是localhost:18080
proxy_set_header Host $http_host;
# 把cookie中的path部分从/api替换成/service
proxy_cookie_path /api /;
# 把cookie的path部分从localhost:18080替换成your.domain.name
proxy_cookie_domain localhost:18080 tosim.top;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# CORS
CORS(Cross-Origin Resource Sharing)是指跨域资源共享,它是一个W3C机制,能够允许服务器标识除了它自己以外的其它域,这样浏览器就可以进行跨域访问加载资源。具体表现为浏览器会对响应进行一个CORS规则的校验,校验通过就不拦截响应,正常接收展示,拦截了,就是跨域问题。
简单来说就是资源是服务器的,只要服务器都同意了这个请求所请求的资源可以被使用,那浏览器也就不会拦截,服务器没有表态或者明确说拒绝,浏览器就会对该响应进行拦截,不进行解析。
具体流程
(1)请求端: 当发起一个跨域请求时,浏览器会自动在请求头中加入 Origin 字段,它是发起方所处于的域,表明了“来源”。
示例:请求中含有
Origin: http://foo.example
2
(2)服务端: 服务端根据“来源” 来决定处理方式,如果同意,则返回的消息头中添加 Access-Control-Allow-Origin 字段。这个字段的值可以是“ * ”(表示任意的域名都允许),或者是具体的域名地址。实际情况下不可能是“*”,而是具体的源的域名,表明该域名可以接收本次的响应信息。
Access-Control-Allow-Origin: *
以上是简单请求的流程,非简单请求会在正式请求前进行一次预检请求,(非简单请求主要是该请求存在某些特殊操作,比如该请求是delete,Put请求需要对服务器资源进行修改)目的是在于向服务器确认将要访问服务器的正式请求的域名是否在服务器许可的安全域名名单之内,以及可以发送哪些http类型的请求等。
之后的正式请求就和简单请求一样了。
具体做法
核心即在我们所有响应头配置允许跨域访问,CORS也已经成为主流的跨域解决方案。
- 在项目中创建一个新的配置文件
- 添加
@Configuration
注解实现WebMvcConfigurer
接口 - 重写
addCorsMappings
方法并设置允许跨域的代码
具体代码如下:
java复制代码import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 所有接口
.allowCredentials(true) // 是否发送 Cookie
.allowedOriginPatterns("*") // 支持域
.allowedMethods("GET", "POST", "PUT", "DELETE") // 支持方法
.allowedHeaders("*")
.exposedHeaders("*");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
这种方式和上面的方式类似,也是通过Java Config
的方式配置跨域访问, 通过 CorsFilter 解决跨域。
具体代码如下:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class MyCorsFilter {
@Bean
public CorsFilter corsFilter() {
// 1.创建 CORS 配置对象
CorsConfiguration config = new CorsConfiguration();
// 支持域
config.addAllowedOriginPattern("*");
// 是否发送 Cookie
config.setAllowCredentials(true);
// 支持请求方式
config.addAllowedMethod("*");
// 允许的原始请求头部信息
config.addAllowedHeader("*");
// 暴露的头部信息
config.addExposedHeader("*");
// 2.添加地址映射
UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
corsConfigurationSource.registerCorsConfiguration("/**", config);
// 3.返回 CorsFilter 对象
return new CorsFilter(corsConfigurationSource);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 最佳实践
生产环境中,最好是在服务端的入口出解决跨越问题,比如通过nginx或者API网关解决跨域问题, 这样我们的每个微服务就不需要关注跨域的问题。单体服务的话直接在后端项目配置跨域即可。