跨域校驗(yàn)是瀏覽器的行為妥泉,旨在提升不同站點(diǎn)訪問的安全性椭微。在提升安全性的同時(shí)也增加了開發(fā)者的開發(fā)難度,為了解決跨域問題盲链,開發(fā)者們想出了一些列解決方案蝇率,來允許跨域(更確切地說是在可控范圍內(nèi)允許跨域)。在前后端分離流行的今天刽沾,前端和后端都發(fā)展出了解決跨域的方法本慕,本篇文章主要講解后端的跨域解決方案。
1侧漓、跨域問題本地測試
在本地搭建前端锅尘、后端服務(wù),用花生殼做內(nèi)網(wǎng)穿透布蔗,前端接口調(diào)用指向穿透鏈接藤违。即可模擬跨域場景,同時(shí)也可以在本地調(diào)試纵揍《倨梗【只要端口不同,不用做內(nèi)網(wǎng)穿透也是可以重現(xiàn)跨域場景的】
2泽谨、服務(wù)端跨域解決方案
新增filter璧榄,設(shè)置響應(yīng)header的跨域參數(shù)特漩。
參數(shù)包括:
Access-Control-Allow-Origin:允許跨域的請求發(fā)起源網(wǎng)站。不要粗暴的寫成"*"骨杂,要從請求頭中獲取origin涂身,明確具體的來源。
Access-Control-Allow-Credentials:允許客戶端攜帶驗(yàn)證信息搓蚪。若前端設(shè)置了withCredentials: true則此處必須設(shè)置為true访得。
Access-Control-Allow-Methods:允許跨域的方法。GET\POST\PUT\DELETE
Access-Control-Max-Age
Access-Control-Allow-Headers
在解決跨域問題時(shí)也要注意瀏覽器的提示陕凹,有的放矢,不要胡亂猜測鳄炉,一通操作杜耙。
The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '' when the request's credentials mode is 'include'.
檢查Access-Control-Allow-Origin是否設(shè)置成,改成具體的前端網(wǎng)址地址拂盯,或者((HttpServletRequest) servletRequest).getHeader("origin")即可佑女。
The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.
檢查Access-Control-Allow-Credentials是否設(shè)置成true。
3谈竿、復(fù)雜請求put和delete的跨域解決方案
有些同學(xué)設(shè)置了跨域后团驱,發(fā)現(xiàn)put和delete依然存在跨域,其原因是put和delete為復(fù)雜請求空凸,復(fù)雜請求會先發(fā)起options請求嚎花,判斷服務(wù)器是否支持后續(xù)的請求,所以不能簡單的return呀洲,return前需要將put紊选,delete等配置好跨域。見代碼中的setHeader方法道逗。
4兵罢、代碼
隨便找個(gè)目錄放進(jìn)去就可以了。
package pro.haichuang.ktwelve.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.web.bind.annotation.RequestMethod;
import java.io.IOException;
import org.springframework.http.HttpStatus;
import pro.haichuang.ktwelve.util.L;
@Configuration
@Order(value = 0)
@WebFilter(filterName = "CorsFilterConfig", urlPatterns = "/*")
public class CorsFilterConfig implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
L.i(new Throwable().getStackTrace()[0] + "===============CorsFilterConfig執(zhí)行=================");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) servletResponse;
String origin = ((HttpServletRequest) servletRequest).getHeader("origin");
res.setHeader("Access-Control-Allow-Origin", origin);
res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
res.setHeader("Access-Control-Allow-Credentials", "true");
res.setHeader("Access-Control-Max-Age", "1728000");
res.setHeader("Access-Control-Allow-Headers", "Authentication, Authorization, content-type, Accept, x-requested-with, Cache-Control");
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
String requestMethod = httpRequest.getMethod();
if (requestMethod.equals(RequestMethod.OPTIONS.name())) {
setHeader(httpRequest, httpResponse);
return;
}
filterChain.doFilter(servletRequest, res);
}
private void setHeader(HttpServletRequest request, HttpServletResponse response) {
//跨域的header設(shè)置
String origin = request.getHeader("origin");
response.setHeader("Access-Control-Allow-Origin", origin);
//這句可以解決當(dāng)請求為put和delete時(shí)的跨域問題
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));
//防止亂碼滓窍,適用于傳輸JSON數(shù)據(jù)
response.setHeader("Content-Type", "application/json;charset=UTF-8");
response.setStatus(HttpStatus.OK.value());
}
@Override
public void destroy() {
}
}