背景
前端访问后台如果不想走代理模式,则需要在后台进行配置,允许跨域访问,本文对配置过程进行总结。
跨域介绍
跨域请求指的是在 Web 应用程序中,通过 JavaScript 代码向另一个域名(或端口、协议)发起 AJAX 请求。跨域请求分为简单跨域请求和复杂跨域请求。
简单跨域请求
如果 AJAX 请求满足以下所有条件,则称其为简单跨域请求:
- 请求方法只能是 GET、POST 或 HEAD
- HTTP 请求头限制:只能包含
Accept
、Accept-Language
、Content-Language
、Content-Type
(仅限于application/x-www-form-urlencoded
、multipart/form-data
、text/plain
) - 允许跨域访问的 HTTP 响应头:
Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
、Pragma
对于简单跨域请求,浏览器会自动向服务端发送一个额外的 Origin
头信息,用来说明请求来自哪个源(即域名、端口或协议)。服务端可以根据这个头信息来确定是否允许该跨域请求。
复杂跨域请求
除了简单跨域请求以外的所有跨域 AJAX 请求都被视为复杂跨域请求。简单跨域请求以外的 AJAX 请求,都会先进行一次预检,然后才会真正发出请求。
预检请求使用 OPTIONS 方法,向服务端发送以下信息:
- Access-Control-Request-Method:请求的方法(比如 GET、POST 等)
- Access-Control-Request-Headers:请求头信息
服务端需要对这个预检请求进行响应,响应中包含以下信息:
- Access-Control-Allow-Origin:允许跨域访问的源
- Access-Control-Allow-Methods:允许使用的 HTTP 方法
- Access-Control-Allow-Headers:允许包含的 HTTP 请求头
- Access-Control-Max-Age:预检结果的有效期
只有在收到了正确的预检响应后,浏览器才会发出真正的 AJAX 请求。
解决方式
1、新建配置类CorsConfig
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 CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 设置允许跨域的路径
registry.addMapping("/**")
// 设置允许跨域请求的域名
.allowedOrigins("*")
// 这里:是否允许证书 不再默认开启
.allowCredentials(true)
// 设置允许的方法
.allowedMethods("*")
// 跨域允许时间
.maxAge(3600);
}
}
2、新建过滤器CorsFilter(解决预检错误问题:Response to preflight request doesn't pass access control check: It does not have HTTP ok status.)
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@WebFilter(filterName = "corsFilter", urlPatterns = "/*")
public class CorsFilter implements Filter {
private static final String OPTIONS = "OPTIONS";
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
res.addHeader("Access-Control-Allow-Credentials", "true");
res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Methods", "*");
res.addHeader("Access-Control-Allow-Headers", "*");
res.addHeader("Access-Control-Max-Age", "3600");
// 如果是OPTIONS则结束请求
if (OPTIONS.equals(((HttpServletRequest) request).getMethod())) {
response.getWriter().println("ok");
return;
}
chain.doFilter(request, response);
}
}