springboot 如何解決cross跨域請(qǐng)求的問(wèn)題
springboot 解決cross跨域請(qǐng)求
1.使用ajax發(fā)送跨域請(qǐng)求接口時(shí)
接口能正常接收到請(qǐng)求并響應(yīng),但是無(wú)法正常展示響應(yīng)數(shù)據(jù)。跨域請(qǐng)求時(shí)會(huì)在有一個(gè)特別的請(qǐng)求頭origin(請(qǐng)求來(lái)源)。
瀏覽器認(rèn)為這是不安全的。需要在被跨域請(qǐng)求的那個(gè)接口,響應(yīng)時(shí)加上加上幾個(gè)響應(yīng)頭讓瀏覽器允許跨域請(qǐng)求的響應(yīng)數(shù)據(jù)展示。
springboot準(zhǔn)備了一個(gè)過(guò)濾器來(lái)實(shí)現(xiàn)這個(gè)操作。(如下:8081有個(gè)ajax請(qǐng)求8888的接口,需要在8888加上過(guò)濾器)

2.在被跨域請(qǐng)求的一方配置
一個(gè)CrosFilter過(guò)濾器到spring里即可
@Bean
public CorsFilter corsFilter() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("http://localhost:8081"); // 允許的域名白名單,可以*
corsConfiguration.addAllowedHeader("*"); // 允許任何頭
corsConfiguration.addAllowedMethod(HttpMethod.POST); // 允許哪些類型請(qǐng)求,可以*
corsConfiguration.addExposedHeader("my-header");//自定義請(qǐng)求頭
corsConfiguration.setAllowCredentials(true);//是否允許攜帶cookie
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/sys/generator/list", corsConfiguration); // 哪些path的接口可以被跨域請(qǐng)求
source.registerCorsConfiguration("/sys/generator/code", corsConfiguration);
return new CorsFilter(source);
}
3.再次測(cè)試
響應(yīng)頭主要多了這些,也能正常接收到響應(yīng)數(shù)據(jù)了

4.對(duì)于只有個(gè)別需要開放跨域請(qǐng)求的接口可以這樣玩
@CrossOrigin的參數(shù)跟CrosFilter參數(shù)設(shè)置過(guò)濾器一致。

5.其它解決跨域請(qǐng)求的常用方法
使用Nginx反向代理 或前端不跨域請(qǐng)求,后端專門開放一個(gè)API接口供前端調(diào)用,接口以httpClient請(qǐng)求數(shù)據(jù)
Spring解決cross domain
Spring4:
在requestMapping中使用注解。 @CrossOrigin(origins = “http://localhost:9000”)
全局實(shí)現(xiàn) .定義類繼承WebMvcConfigurerAdapter
public class CorsConfigurerAdapter extends WebMvcConfigurerAdapter{ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/*").allowedOrigins("*"); } }
將該類注入到容器中:
<bean class="com.tmall.wireless.angel.web.config.CorsConfigurerAdapter"></bean>
Spring3舊版本:
在org.springframework.web.servlet.DispatcherServlet.doDispatch中會(huì)根據(jù)根據(jù)request來(lái)獲取HandlerExecutionChain,SpringMVC在獲取常規(guī)的處理器后會(huì)檢查是否為跨域請(qǐng)求,如果是則替換原有的實(shí)例。
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); if (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; }
檢查的方法也很簡(jiǎn)單,即檢查請(qǐng)求頭中是否有origin字段
public static boolean isCorsRequest(HttpServletRequest request) { return (request.getHeader(HttpHeaders.ORIGIN) != null); }
請(qǐng)求接著會(huì)交由 HttpRequestHandlerAdapter.handle來(lái)處理,根據(jù)handle不同,處理不同的邏輯。前面根據(jù)請(qǐng)求頭判斷是一個(gè)跨域請(qǐng)求,獲取到的Handler為PreFlightHandler,其實(shí)現(xiàn)為:
@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws IOException { corsProcessor.processRequest(this.config, request, response); }
繼續(xù)跟進(jìn)
@Override
public boolean processRequest(CorsConfiguration config, HttpServletRequest request, HttpServletResponse response)
throws IOException {
if (!CorsUtils.isCorsRequest(request)) {
return true; } ServletServerHttpResponse serverResponse = new ServletServerHttpResponse(response); ServletServerHttpRequest serverRequest = new ServletServerHttpRequest(request); if (WebUtils.isSameOrigin(serverRequest)) { logger.debug("Skip CORS processing, request is a same-origin one"); return true; } if (responseHasCors(serverResponse)) { logger.debug("Skip CORS processing, response already contains \"Access-Control-Allow-Origin\" header"); return true; } boolean preFlightRequest = CorsUtils.isPreFlightRequest(request); if (config == null) { if (preFlightRequest) { rejectRequest(serverResponse); return false; } else { return true; } } return handleInternal(serverRequest, serverResponse, config, preFlightRequest); }
此方法首先會(huì)檢查是否為跨域請(qǐng)求,如果不是則直接返回,接著檢查是否同一個(gè)域下,或者response頭里是否具有Access-Control-Allow-Origin字段或者request里是否具有Access-Control-Request-Method。
如果滿足判斷條件,則拒絕這個(gè)請(qǐng)求。
由此我們知道,可以通過(guò)在檢查之前設(shè)置response的Access-Control-Allow-Origin頭來(lái)通過(guò)檢查。我們?cè)跀r截器的preHandle的處理。加入如下代碼:
response.setHeader("Access-Control-Allow-Origin", "*");
此時(shí)瀏覽器中OPTIONS請(qǐng)求返回200。但是依然報(bào)錯(cuò):
Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
我們注意到:在request的請(qǐng)求頭里有Access-Control-Request-Headers:accept, content-type,但是這個(gè)請(qǐng)求頭的中沒有,此時(shí)瀏覽器沒有據(jù)需發(fā)送請(qǐng)求。嘗試在response中加入:
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
執(zhí)行成功:
Object {userId: 123, userName: “adminUpdate-wangdachui”}
至此:我們通過(guò)分析原理使SpringMVC實(shí)現(xiàn)跨域,原有實(shí)現(xiàn)以及客戶端代碼不需要任何改動(dòng)。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot實(shí)現(xiàn)接口冪等性的4種方案
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)接口冪等性的4種方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
Spring學(xué)習(xí)之開發(fā)環(huán)境搭建的詳細(xì)步驟
本篇文章主要介紹了Spring學(xué)習(xí)之開發(fā)環(huán)境搭建的詳細(xì)步驟,具有一定的參考價(jià)值,有興趣的可以了解一下2017-07-07
如何在SpringBoot 中使用 Druid 數(shù)據(jù)庫(kù)連接池
這篇文章主要介紹了SpringBoot 中使用 Druid 數(shù)據(jù)庫(kù)連接池的實(shí)現(xiàn)步驟,幫助大家更好的理解和學(xué)習(xí)使用SpringBoot,感興趣的朋友可以了解下2021-03-03
使用kotlin集成springboot開發(fā)的超詳細(xì)教程
目前大多數(shù)都在使用java集成 springboot進(jìn)行開發(fā),本文演示僅僅將 java換成 kotlin,其他不變的情況下進(jìn)行開發(fā),需要的朋友可以參考下2021-09-09
SpringBoot 如何使用 JWT 保護(hù) Rest Api&nbs
使用spring-boot開發(fā)RESTful API非常的方便,在生產(chǎn)環(huán)境中,對(duì)發(fā)布的 API 增加授權(quán)保護(hù)是非常必要的,現(xiàn)在我們來(lái)看如何利用JWT技術(shù)為API 增加授權(quán)保護(hù),保證只有獲得授權(quán)的用戶才能夠訪問(wèn) API,感興趣的朋友跟隨小編一起看看吧2024-02-02
java高并發(fā)ScheduledThreadPoolExecutor類深度解析
這篇文章主要為大家介紹了java高并發(fā)ScheduledThreadPoolExecutor類源碼深度解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
SpringMVC自定義類型轉(zhuǎn)換器實(shí)現(xiàn)解析
這篇文章主要介紹了SpringMVC自定義類型轉(zhuǎn)換器實(shí)現(xiàn)解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12

