最近Vue項目中使用axios組件,在頁面交互中發現axios會發送兩次請求,一種請求方式為OPTIONS,另外一種為自己設置的。
如圖:


什么是CORS通信?
CORS是一個W3C標准,全稱是"跨域資源共享"(Cross-origin resource sharing)。 它允許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。
CORS需要瀏覽器和服務器同時支持。目前,所有瀏覽器都支持該功能,IE瀏覽器不能低於IE10。
實現CORS通信的關鍵是服務器。只要服務器實現了CORS接口,就可以跨域通信。詳情見:前后分離調用API接口跨域問題
CORS兩種請求
瀏覽器將CORS請求分成兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)。
只要同時滿足以下兩大條件,就屬於簡單請求。
(1) 請求方法是以下三種方法之一:
- HEAD
- GET
- POST
(2)HTTP的頭信息不超出以下幾種字段:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限於三個值
application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不同時滿足上面兩個條件,就屬於非簡單請求。
非簡單請求是那種對服務器有特殊要求的請求,比如請求方法是PUT或DELETE,或者Content-Type字段的類型是application/json。
非簡單請求的CORS請求,會在正式通信之前,增加一次HTTP查詢請求,稱為"預檢"請求(preflight)。
瀏覽器先詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,以及可以使用哪些HTTP動詞和頭信息字段。只有得到肯定答復,瀏覽器才會發出正式的XMLHttpRequest請求,否則就報錯。
瀏覽器對這兩種請求的處理,是不一樣的。
兩次請求原因
前后端未滿足“同源策略/SOP”,俗稱請求跨域。瀏覽器一旦發現請求跨域,就會使用CORS通信,自動添加一些附加的頭信息,簡單請求只會有一次請求,只有非簡單請求會附加一次請求。
解決方法
服務期端直接通過“預檢”請求,服務器新建攔截器,攔截所有請求,篩選所有Requset Method:OPTIONS的請求,不做任何處理直接返回即可。
以下是JAVA設置:
package com.yhzy.zytx.jwt.Interceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
/**
* @ClassName JwtInterceptor
* @Description JWT攔截器
* @Author 天生傲骨、怎能屈服
* @Date 2019/5/22 13:48
* @Version 1.0
*/
public class JwtInterceptor implements HandlerInterceptor {
private final static Logger logger = LoggerFactory.getLogger(JwtInterceptor.class);
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
// 從 http 請求頭中取出 token
String token = httpServletRequest.getHeader("Authorization");
// 如果不是映射到方法直接通過
if(!(object instanceof HandlerMethod)){
return true;
}
HandlerMethod handlerMethod=(HandlerMethod)object;
Method method=handlerMethod.getMethod();
// OPTIONS請求類型直接返回不處理
if ("OPTIONS".equals(httpServletRequest.getMethod())){
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, Exception e) throws Exception {
}
}
