1.场景描述
后端老服务是单体服务集成security 新增加微服务,服务没有集成security,有跨域浏览器 老服务中有token验证,新服务中没有token验证
这样产生的一个问题就是,当浏览器调用新服务接口的时候,出现跨域问题
2. 问题排查过程
1)看下请求有没有到后端(没有)
2)用charls,看浏览器有没有发送OPTIONS请求(发送了)
3)对比原有正确的请求和新增接口跨域请求,返回的报文是否一致(不一致)
正确的报文
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: http://192.168.17.152:8000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: content-type, token
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 3600
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 0
Date: Sun, 07 Apr 2024 02:43:22 GMT
Keep-Alive: timeout=60
Proxy-Connection: keep-alive
有问题的报文:
HTTP/1.1 200
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, PUT, GET, OPTIONS, DELETE
Access-Control-Max-Age: 3600
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, client_id, uuid, Authorization
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Allow: GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH
Content-Length: 0
Date: Sun, 07 Apr 2024 02:38:13 GMT
Keep-Alive: timeout=60
Proxy-Connection: keep-alive
4)模拟请求,发现旧项目的OPTIONS请求是security框架返回的,而新项目是CrosFilter返回的,所有两个不一样
3.问题原因
浏览器认为后端服务是有token凭据验证的,返回的报文中需要有Access-Control-Allow-Credentials: true,当有Access-Control-Allow-Credentials: true的时候Access-Control-Allow-Origin属性不能是*
旧项目OPTIONS请求返回时security框架返回 新项目是CrosFilter返回的,所以两者返回的不一样
实际是增加token产生的影响
4.解决方案
修改跨域Filter
import lombok.extern.slf4j.Slf4j;
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;
/**
* 跨域请求处理
*/
@Slf4j
@WebFilter(filterName = "CrosFilter ", urlPatterns = "/*")
@Component
public class CrosFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse response = (HttpServletResponse) resp;
String method1 = req.getMethod();
System.out.println("method1:" + method1);
String method = req.getHeader("Access-Control-Request-Method");
String origin = req.getHeader("Origin");
//解决跨域访问报错
// response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Origin", origin);
// response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Methods", method);
//设置过期时间
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, client_id, uuid, token, Authorization");
// 支持HTTP 1.1.
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
// 支持HTTP 1.0. response.setHeader("Expires", "0");
response.setHeader("Pragma", "no-cache");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("X-Content-Type-Options", "nosniff");
response.setHeader("X-XSS-Protection", "1; mode=block");
response.setHeader("X-Frame-Options", "DENY");
// 编码
response.setCharacterEncoding("UTF-8");
chain.doFilter(request, resp);
}
@Override
public void init(FilterConfig filterConfig) {
log.info("跨域过滤器启动");
}
@Override
public void destroy() {
log.info("跨域过滤器销毁");
}
}