背景:
在做前后端分離時,牽扯到跨域,但是已經設置了跨域
前端設置了允許攜帶Cookie
axios.defaults.withCredentials = true;
后端也配置了跨域
瀏覽器端查看發送的請求,請求頭中包含Authorization
原因:
實際上發送了兩次請求,第一次為OPTIONS
請求,第二次才GET/POST...
請求
- 在
OPTIONS
請求中,不會攜帶請求頭的參數,所以在攔截器上獲取請求頭為空,自定義的攔截器攔截成功 - 第一次請求不能通過,就不能獲取第二次的請求了
GET/POST...
第一次請求不帶參數,第二次請求才帶參數
解決:
在攔截器中,如果請求為OPTIONS
請求,讓 OPTIONS
請求返回一個200狀態碼,表示可以正常訪問,然后就會收到真正的GET/POST
請求
String method = request.getMethod(); //輸出 OPTIONS/GET/POST。。。
//如果是 OPTIONS 請求,讓 OPTIONS 請求返回一個200狀態碼
if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
return false;
}
攔截器完整示例
@Component
public class HttpRequestInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//origin:指定可以訪問本項目的IP
String origin = request.getHeader("Origin");
response.setContentType("application/json;charset=UTF-8");
response.setHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "1800");
// 設置 受支持請求標頭(自定義 可以訪問的請求頭 例如:Token)
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,Authorization,token,Origin,Content-Type,Accept");
// 指示的請求的響應是否可以暴露於該頁面。當true值返回時它可以被暴露
response.setHeader("Access-Control-Allow-Credentials", "true");
//如果是OPTIONS請求,讓其響應一個 200狀態碼,說明可以正常訪問
if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
配置攔截器
自定義的攔截器必須要配置,才能使用
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private HttpRequestInterceptor httpRequestInterceptor;
// 配置攔截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
//設置跨域得攔截器 ,/** 表示攔截所有請求
registry.addInterceptor(httpRequestInterceptor).addPathPatterns("/**");
}
}