跨域解决方案
1.跨域基本介绍
文档:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS
跨域问题是什么?
一句话:跨域指的是浏览器不能执行其他网站的脚本,它是由浏览器的同源策略造成的,是浏览器对 javascript 施加的安全限制。
说明:跨域是浏览器对 javascript 施加的安全限制,而不是服务端的安全限制,也就是说,只要请求满足接口规范,就返回数据
同源策略
- 同源策略是一种约定,它是浏览器最核心也最基本的安全功能
- 如果缺少了同源策略,浏览器很容易受到 XSS(跨站脚本攻击)、CSFR(跨站请求伪造)等攻
击 - 所谓同源是指 协议、域名、端口 三者都要相同,其中一个不同,就属于非同源,就会
产生跨域问题 - 看一张图
2.跨域流程
2.1 简单请求和非简单请求
简单请求: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS
- 只要同时满足以下两大条件,就属于简单请求
条件 1:使用下列方法之一:
GET
HEAD
POST
条件 2:Content-Type 的值仅限于下列三者之一:
text/plain(文本文件格式)
multipart/form-data(当表单包含文件上传时, 编码类型需要设置为 multipart/form-data)
application/x-www-form-urlencoded(当表单数据不包含文件上传等复杂数据时,通常使用这种编码类型进行表单提交, 表单数据被编码为键值对的形式)
非简单请求/复杂请求:不符合简单请求条件的请求就是非简单请求/复杂请求
3.跨域解决方案
3.1方式 1-nginx 反向代理
- 将前端项目和后端项目统一放在 Nginx 的管理下
- Nginx 对外提供统一的访问域名
- 当请求达到 Nginx 时,使用 Nginx 的反向代理+动静分离,实现各找各妈的效果
3.2方式 2-配置服务器允许跨域
- 后端服务返回时,添加响应头
Access-Control-Allow-Origin∶支持哪些来源的请求跨域
Access-Control-Allow-Methods∶支持哪些方法跨域
Access-Control-Allow-Credentials∶ 跨域请求默认不包含 cookie,设置为 true 可以包含cookie
Access-Control-Expose-Headers∶跨域请求暴露的字段
CORS 请求时,XMLHttpRequest 对象的 getResponseHeader(()方法只能拿到 6 个基本字
段∶Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。
如果想拿到其他字段,就必须在 Access-Control-Expose-Headers 里面指定。
Access-Control-Max-Age∶表明该响应的有效时间为多少秒。在有效时间内,浏览器无须为同一请求再次发起预检请求。请注意,浏览器自身维护了一个最大有效时间,如果该首部字段的值超过了最大有效时间,将不会生效。
- 简单原理示意图/抓包
3.3方式 3-前端使用代理,配置同源(VUE)
- 在 VUE 项目中启用代理,设置同源 具体配置
module.exports = {
devServer: {
port: 10000, // 启动端口ctrl+alt+l
proxy: { //设置代理,必须填
'/api': { //设置拦截器 拦截器格式 斜杠+拦截器名字,名字可以自己定
target: 'http://localhost:9090', //代理的目标地址, 就是/api 代替 http://localhost:9090
changeOrigin: true, //是否设置同源,设置的是true, 实现跨域
pathRewrite: { //路径重写
'/api': '' //选择忽略拦截器里面的单词
}
}
}
}
}
3.4其它方式(这些解决方式都有一些前提条件)
jsonp
postMessage
websocket
Node 中间件代理(两次跨域)
window.name + iframe
location.hash + iframe
document.domain + iframe
4.跨域实操
4.1 实现跨域方法 1-全局 cors 配置
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;
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
//创建跨域配置,添加 CORS 配置信息
final CorsConfiguration corsConfiguration = new CorsConfiguration();
//跨域请求默认不包含 cookie,设置为 true 可以包含 cookie
corsConfiguration.setAllowCredentials(true);
//支持哪些来源的请求跨域, 支持
corsConfiguration.addAllowedOriginPattern("*");
//corsConfiguration.addAllowedOrigin("*");
//支持哪些头信息
corsConfiguration.addAllowedHeader("*");
//支持哪些方法跨域
corsConfiguration.addAllowedMethod("*");
//添加映射路径
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
// /** 是一个正则表达式,表示所有请求 the mapping pattern
// corsConfiguration 跨域配置
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
//返回新的 CorsFilter.
return new CorsFilter(urlBasedCorsConfigurationSource);
}
}
4.2实现跨域方法 2-添加 cors 配置类(全局跨域)
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
.maxAge(3600)
.allowCredentials(true);
}
}
4.3实现跨域方法 3-使用 Filter 方法
@WebFilter(urlPatterns = "*")
public class CorsFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain
filterChain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setCharacterEncoding("UTF-8");
httpResponse.setContentType("application/json; charset=utf-8");
httpResponse.setHeader("Access-Control-Allow-Origin", "*");
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
httpResponse.setHeader("Access-Control-Allow-Methods", "*");
httpResponse.setHeader("Access-Control-Allow-Headers", "Content-Type,Authorization");
httpResponse.setHeader("Access-Control-Expose-Headers", "*");
filterChain.doFilter(httpRequest, httpResponse);
}
@Override
public void destroy() {
}
}
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@ServletComponentScan
@MapperScan(basePackages = {"com.llp.furn.mapper"})
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4.4实现跨域方法 4-VUE 项目启用代理,配置同源
module.exports = {
devServer: {
port: 10000, // 启动端口ctrl+alt+l
proxy: { //设置代理,必须填
'/api': { //设置拦截器 拦截器格式 斜杠+拦截器名字,名字可以自己定
target: 'http://localhost:9090', //代理的目标地址, 就是/api 代替 http://localhost:9090
changeOrigin: true, //是否设置同源,设置的是true, 实现跨域
pathRewrite: { //路径重写
'/api': '' //选择忽略拦截器里面的单词
}
}
}
}
}