坑爹的問題
最近在項(xiàng)目中遇到一個(gè)跨域問題阻逮,坑了好久容诬,查閱了很多資料終于解決了娩梨,特此記錄。
問題描述
前端庫我這邊用的axios览徒。后臺是java狈定。前臺請求方法是post。token驗(yàn)證放在header里面?zhèn)鞯胶笈_习蓬。
前端代碼如下:
axios.defaults.baseURL = getAppParams().host;
axios.defaults.headers.common['token'] = getAppParams().token;
axios({
method: "post",
url: 'order/ordcustomer/save',
data: formdata,
transformRequest: [function(data) {
return JSON.stringify(data)
}]
})
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err)
})
瀏覽器會提示這樣:Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed
纽什。
一些概念
一番查詢后發(fā)現(xiàn)。當(dāng)后臺設(shè)置Content-Type:application/json
的時(shí)候躲叼,前端請求為post的時(shí)候芦缰,即為復(fù)雜請求。這時(shí)候枫慷,瀏覽器一次post請求會變成兩次饺藤。
- 第一次瀏覽器會優(yōu)先發(fā)送一個(gè)
options
給后臺,后臺驗(yàn)證通過 - 開始發(fā)送真正的post請求
關(guān)于預(yù)檢的概念網(wǎng)上有很多流礁,我這邊就不記錄了。傳送門
解決方法
這個(gè)問題還是得從后臺解決罗丰。 這是后臺的修改代碼神帅。
后臺框架shiro
servlet filter
部分
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletResponse resp = (HttpServletResponse) response;
HttpServletRequest rep = (HttpServletRequest) request;
resp.addHeader("Access-Control-Allow-Origin",rep.getHeader("Origin"));
//允許跨域請求中攜帶cookie
resp.addHeader("Access-Control-Allow-Credentials", "true");
// 如果存在自定義的header參數(shù),需要在此處添加萌抵,逗號分隔
resp.addHeader("Access-Control-Allow-Headers", "authorization,Origin, No-Cache, X-Requested-With, "
+ "If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, " + "Content-Type, X-E4M-With");
resp.addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
chain.doFilter(request, response);
}
好多網(wǎng)上推薦的是找御,將resp.addHeader("Access-Control-Allow-Origin",*);
因?yàn)檫@邊已經(jīng)設(shè)置了Access-Control-Allow-Credentials:true
元镀,所以前端跨域的時(shí)候時(shí)候會帶上cookie
。這樣在請求的時(shí)候就會產(chǎn)生沖突霎桅。所以一定要將Access-Control-Allow-Origin
設(shè)置成rep.getHeader("Origin")
!!! 傳送門
還有一個(gè)細(xì)節(jié)就是栖疑,后臺還要判斷一下獲取的請求,判斷此次是否是預(yù)檢請求(即getHeader()=="OPTIONS"
)滔驶,如果相同則 return true
允許跨域遇革;預(yù)檢后,正式請求揭糕。
if (((HttpServletRequest) request).getMethod().equals("OPTIONS")){
return true;
} else{
//萝快。。著角。揪漩。。吏口。奄容。。产徊。昂勒。。囚痴。叁怪。
}