彻底搞懂什么是跨域以及如何解决跨域问题?
什么是跨域?
跨域是指一个域名网页尝试访问另一个域名下的数据或资源时,由于浏览器的同源策略限制而产生的行为。同源策略是一种安全机制,它要求网页只能访问本域名下的服务器数据或资源。当协议、域名或端口中有任意一个不同时,就会产生跨域问题。例如:当本地8080端口请求8081端口数据时,会产生跨域异常,如下:
为什么会产生跨域问题?
跨域问题的产生主要是由于以下几个原因:
- 安全性:同源策略可以防止网站数据被其它恶意网站读取或修改
- 隐私保护:本网站数据内容应该受到保护,不应该被其它网站访问
- 内容隔离:浏览器为了保护用户的安全,将不同源的内容进行隔离
如何解决跨域问题?
在Java后端开发中,解决跨域问题通常有以下几种方法:
1. CORS (Cross-Origin Resource Sharing)
当出现跨域请求时,浏览器通常会发起两次请求:一个预检请求和一个实际请求。为了处理跨域请求,CORS(跨源资源共享)机制允许服务器标示除了它自己以外的其他源,使得浏览器允许这些源访问加载自己的资源。CORS通过预检(HTTP OPTIONS)请求来检查服务器是否会允许要发送的真实请求。在预检中,浏览器发送的头中带有HTTP方法和真实请求中会用到的头信息。如果服务器响应表示允许该跨域请求,则浏览器会继续发送实际的请求。
CORS是一种W3C标准,它允许服务器放宽同源策略的限制。在跨域请求中,浏览器会自动添加一些特定的头部信息,如Origin
和Referer
,并且不允许修改某些头部信息,如Content-Type
,除非服务器允许。通过在响应头中添加特定的CORS头信息,可以实现跨域资源共享。
@CrossOrigin注解
通过@CrossOrigin
注解实现方法或类跨域支持,但这种处理方法只适合少量接口支持跨域请求,当大量接口支持跨域请求时,每个接口或类上都需要添加,比较麻烦,而且如果忘记了会导致前端请求异常
@RestController
@RequestMapping("/cros")
public class TestController {
@CrossOrigin(origins = "*")
@GetMapping("/test")
public String list() {
return "Success";
}
}
实现WebMvcConfigurer接口
实现WebMvcConfigurer接口并重写全局跨域规则,该规则全局生效,当大量接口支持跨域时,可在此一次性添加跨域规则
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/cros/**")
.allowCredentials(true)
.allowedOrigins("http://localhost:8080")
.allowedMethods("GET")
.allowedHeaders("*")
.exposedHeaders("**");
}
}
自定义CorsFilter过滤器
创建跨域配置类, 并在类中自定义跨域过滤器,设置自定义跨域规则,该规则同样全局生效。
@Configuration
public class CrosConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("http://localhost:8080");
config.setAllowCredentials(true);
config.addAllowedMethod("GET");
config.addAllowedHeader("*");
config.addExposedHeader("**");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/cros/**", config);
return new CorsFilter(corsConfigurationSource);
}
}
实现Filter接口
添加配置类实现Filter接口并重新doFilter
规则,实现自定义过滤规则。doFilter会在每次请求处理时被调用,对当前请求数据进行特定处理
@Configuration
public class CrosFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("Access-Control-Allow-Origin", "http://localhost:8080");
httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET");
chain.doFilter(request, response);
}
}
2. 使用Nginx配置
前端ajax请求本地路径,并在请求路径中添加固定前缀,如:/api,然后通过修改Nginx的配置,此时所有http://localhost:8080/api/* 请求都会被nginx转发到指定路径,从而解决跨域问题。
在Nginx配置文件中,可以添加以下配置来实现反向代理:
location /api {
proxy_pass http://localhost:8081;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
3. 使用WebSocket
WebSocket是一种通信协议,它允许在单个TCP连接上进行全双工通信,从而绕过了同源策略的限制。
在Java后端,可以使用Java API for WebSocket (JSR 356)来实现WebSocket服务:
@Component
@ServerEndpoint("/websocket")
public class WebsocketServer {
@OnOpen
public void onOpen(Session session) {
// ...
}
@OnMessage
public void onMessage(String message, Session session) {
// ...
}
@OnClose
public void onClose(Session session) {
// ...
}
}
4. 使用document.domain
document.domain是一个用于获取或设置当前文档域名的属性。该方法适用于同一父域下不同子域间的跨域,通过设置document.domain为相同的值来共享数据。例如,在JavaScript中,设置:
document.domain = "example.com";
总结
跨域是Web开发中常见的问题,有多种方法可以解决该问题。在实际开发中,据具体的应用场景和技术要求选择合适的解决方案。同时,需要注意安全性、兼容性以及性能等因素,确保解决方案的可靠性和稳定性。
- 本文标签: java 跨域
- 本文链接: https://www.58cto.cn/article/56
- 版权声明: 本文由程序言原创发布, 非商业性可自由转载、引用,但需署名作者且注明文章出处:程序言 》 彻底搞懂什么是跨域以及如何解决跨域问题? - https://www.58cto.cn/article/56