提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 原理介绍:
- 1.@CrossOrigin注解
- 2.实现WebMvcConfigurer接口
- 3.使用过滤器
- 4.vue代理服务器
- 总结
前言
跨域问题由浏览器的同源策略引起,浏览器限制默认不能给不同源(协议、ip、端口任意一个不同)发送请求,导致前后端无法正常通信。
原理介绍:
本质是服务器处理并返回了响应数据后,浏览器发现是来自不同源的响应数据,所以选择拒接。这个时候我们需要在响应数据的响应头中添加额外配置来让浏览器能成功接收。
所以我们不同的解决方式本质都是要为响应数据的响应头添加额外信息。
但我们现在的主流开发方式是前后端分离,我们使用ajax请求来获取数据时都是在发送跨域请求,所以这是我们不得不解决的问题。
针对这个问题,在springboot和vue的项目结构下,我们有多种解决方案。
1.@CrossOrigin注解
直接在控制类或者控制类的方法上添加@CrossOrigin注解来实现,可以额外指定可以接收哪些域名发送的请求。
以下是接收所有跨域请求:
java">@RestController
@RequestMapping("/user")
@CrossOrigin(origins = "*")
public class UserController { // 控制器方法
}
以下是接收特定域名的跨域请求:
java">@PostMapping("/login")
@CrossOrigin(origins = "http://example.com")
public ResponseEntity<?> login(@RequestBody UserCredentials credentials) {
// 控制器方法
}
2.实现WebMvcConfigurer接口
webMvcConfigurer接口中我们可以重写addCorsMappings方法来配置跨域请求处理方法
java">@Configuration
public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 对所有路径生效 .allowedOrigins("*") // 允许所有源地址 .allowedMethods("GET", "POST", "PUT", "DELETE") // 允许的请求方法 .allowedHeaders("*") // 允许的请求头 .allowCredentials(true) // 是否允许发送Cookie .maxAge(3600); // 预检请求的有效期 }
}
3.使用过滤器
我们可以自己创建一个过滤器,在过滤器中对即将返回的响应数据添加额外的响应头配置。然后将其交给IOC容器管理。
案例代码:
java">import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; @Configuration
public class CorsConfig { @Bean public FilterRegistrationBean<CorsFilter> corsFilter() { FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new CorsFilter()); registrationBean.addUrlPatterns("/*"); registrationBean.setOrder(1); // 设置过滤器的顺序 return registrationBean; } // 也可以使用@WebFilter注解直接定义过滤器,但在此示例中我们通过Java配置类来注册它 public static class CorsFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { // 初始化过滤器(可选) } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse httpResponse = (HttpServletResponse) response; httpResponse.setHeader("Access-Control-Allow-Origin", "*"); httpResponse.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization"); httpResponse.setHeader("Access-Control-Allow-Credentials", "true"); httpResponse.setHeader("Access-Control-Max-Age", "3600"); // 放行chain.doFilter(request, response); } @Override public void destroy() { // 销毁过滤器(可选) } }
}
这样手动添加响应头信息可以帮助我们理解解决跨域问题的本质,但其实spring中已经为我们提供了一个类来帮助我们完成这些工作——CorsFilter
我们只要简单的创建并配置一个CorsFilter对象并其交给IOC管理即可。
案例代码:
java">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 org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** 跨域配置*/
@Configuration
public class CorsConfig {@Beanpublic CorsFilter corsFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();CorsConfiguration corsConfiguration = new CorsConfiguration();corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置return new CorsFilter(source);}
}
4.vue代理服务器
前面说到的几种后端处理跨域请求的方法,本质都是为响应数据添加额外响应头数据来让浏览器接收数据。
但这里使用vue代理服务器的方式解决跨域请求,实际是使用代理服务器来转发我们的请求。
我们可以在vue.config.js(vue2)或vite.config.js(vue3)文件中进行配置.
案例配置:
devServer: {//配置代理,解决跨域问题proxy: {'/api': {//vue项目中所有路径中带api的请求都会进行转发target: 'http://localhost:8080',//目标地址changeOrigin: true,//是否跨域pathRewrite: { '^/api': '' }//路径重写}}}
总结
以上就是在javaweb开发中可以解决跨域问题的几种方式。