亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

解讀SpringBoot中addCorsMappings配置跨域與攔截器互斥問題的原因

 更新時間:2023年12月26日 16:49:18   作者:huangyaa729  
這篇文章主要介紹了解讀SpringBoot中addCorsMappings配置跨域與攔截器互斥問題的原因,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

SpringBoot中addCorsMappings配置跨域與攔截器互斥

如題,前兩天在做前后端分離項目時,碰到了這個問題,登錄token驗證的攔截器使項目中配置的跨域配置失效,導致瀏覽器拋出跨域請求錯誤,跨域配置如下:

public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                        registry.addMapping("/**")
                        .allowedOrigins(origins)
                        .allowedHeaders("*")
                        .allowCredentials(true)
                        .allowedMethods("*")
                        .maxAge(3600);
            }
        };
    }

通過在網(wǎng)上的查詢,發(fā)現(xiàn)了如下解釋

  • 但是使用此方法配置之后再使用自定義攔截器時跨域相關配置就會失效。
  • 原因是請求經(jīng)過的先后順序問題,當請求到來時會先進入攔截器中,而不是進入Mapping映射中,所以返回的頭信息中并沒有配置的跨域信息。瀏覽器就會報跨域異常。

然后參考了網(wǎng)上給出的方法,重新引入了跨域過濾器配置,解決了這個問題。

那最終這個問題產(chǎn)生的原因是什么的,真的如上訴所說嗎,我通過調試與研究源碼,找了原因。

在springMvc中,我們都知道路徑的映射匹配是通過DispatcherServlet這個類來實現(xiàn)的,最終的函數(shù)執(zhí)行在doDispatch()這個方法中:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HttpServletRequest processedRequest = request;
		HandlerExecutionChain mappedHandler = null;
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
			ModelAndView mv = null;
			Exception dispatchException = null;

			try {
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request. 
		(1)mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
		(2)HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

		(3)if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
		(4)mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
		(5)mappedHandler.applyPostHandle(processedRequest, response, mv);
			}

在這個類中,我們關注(1)-(5)這幾句代碼,基本上整個映射執(zhí)行的邏輯就明了了:

  • (1)根據(jù)請求request獲取執(zhí)行器鏈(包括攔截器和最終執(zhí)行方法Handler)
  • (2)根據(jù)Handler獲取handlerAdapter;
  • (3)執(zhí)行執(zhí)行器鏈中的攔截方法(preHandle);
  • (4)執(zhí)行handler方法;
  • (5)執(zhí)行執(zhí)行器鏈中的攔截方法(postHandle);

在這個函數(shù)中我們并沒有看到什么時候執(zhí)行addCorsMappings這一配置內(nèi)容,那它到底是什么時候添加的呢,那就需要仔細分析步驟(1)了:獲取整個執(zhí)行器鏈。

通過調試定位,我發(fā)現(xiàn)getHandle()最終執(zhí)行的AbstractHandlerMapping這個類的函數(shù)

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
(1)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);
		}

(2)HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
		if (CorsUtils.isCorsRequest(request)) {
			CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
			CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
(3)	executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
		}
		return executionChain;
	}

這個函數(shù)中我也標記了(1)、(2)、(3)這三條語句:

  • (1)獲取request所需執(zhí)行的handler,具體邏輯不再細說,有興趣的可以參考我的另一篇文章;
  • (2)獲取執(zhí)行器鏈,簡單來說就是把具體的執(zhí)行器和整個攔截器鏈組成一個鏈隊形,方便后續(xù)執(zhí)行;
  • (3)這個就是關鍵點,可能有的同學已經(jīng)看明白了,addCorsMapping配置就是在這塊引入的;

進入這個方法后,一切都明了了;

protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
			HandlerExecutionChain chain, CorsConfiguration config) {

		if (CorsUtils.isPreFlightRequest(request)) {
			HandlerInterceptor[] interceptors = chain.getInterceptors();
			chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
		}
		else {
			chain.addInterceptor(new CorsInterceptor(config));
		}
		return chain;
	}

先判斷request是否是預檢請求(不明白什么是預檢請求的可以自身搜索相關解釋,很多,不再贅述),是預檢請求則生成個預檢執(zhí)行器PreFlightHandler,然后在doDispatch函數(shù)(4)中執(zhí)行;

否則生成一個跨域攔截器加入攔截器鏈中,最終再doDispatch函數(shù)(3)處執(zhí)行,而因為攔截器是順序執(zhí)行的,如果前面執(zhí)行失敗異常返回后,后面的則不再執(zhí)行。

所以當跨越請求在攔截器那邊處理后就異常返回了,那么響應的response報文頭部關于跨域允許的信息就沒有被正確設置,導致瀏覽器認為服務不允許跨域,而造成錯誤;而當我們使用過濾器時,過濾器先于攔截器執(zhí)行,那么無論是否被攔截,始終有允許跨域的頭部信息,就不會出問題了。

另注:

對于預檢請求,一般token驗證時是不會攔截此請求的,因為預檢請求不會附帶任何參數(shù)信息,也就沒有所需的token信息,所以攔截時需過濾預檢請求

總結

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • MyBatis中的@SelectProvider注解源碼分析

    MyBatis中的@SelectProvider注解源碼分析

    這篇文章主要介紹了MyBatis中的@SelectProvider注解源碼分析,@SelectProvider功能就是用來單獨寫一個class類與方法,用來提供一些xml或者注解中不好寫的sql,今天就來說下這個注解的具體用法與源碼,需要的朋友可以參考下
    2024-01-01
  • Docker和?Containerd?的區(qū)別解析

    Docker和?Containerd?的區(qū)別解析

    containerd?是一個來自?Docker?的高級容器運行時,并實現(xiàn)了?CRI?規(guī)范,它是從?Docker?項目中分離出來,之后?containerd?被捐贈給云原生計算基金會(CNCF)為容器社區(qū)提供創(chuàng)建新容器解決方案的基礎,這篇文章主要介紹了Docker和?Containerd?的區(qū)別,需要的朋友可以參考下
    2024-03-03
  • Java構造方法和方法重載詳解

    Java構造方法和方法重載詳解

    大家好,本篇文章主要講的是Java構造方法和方法重載詳解,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • Java超詳細講解多線程中的Process與Thread

    Java超詳細講解多線程中的Process與Thread

    進程process:在一定的環(huán)境下,把靜態(tài)的程序代碼運行起來,通過使用不同的資源,來完成一定的任務;線程thread:是程序中一個單一的順序控制流程。在單個進程中同時運行多個線程完成不同的工作,稱為多線程
    2022-05-05
  • Java 遞歸查詢部門樹形結構數(shù)據(jù)的實踐

    Java 遞歸查詢部門樹形結構數(shù)據(jù)的實踐

    本文主要介紹了Java 遞歸查詢部門樹形結構數(shù)據(jù)的實踐,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • java中的動態(tài)代理與責任鏈模式詳解

    java中的動態(tài)代理與責任鏈模式詳解

    這篇文章主要介紹了java中的動態(tài)代理與責任鏈模式詳解,動態(tài)代理提供了一種靈活且非侵入式的方式,可以對對象的行為進行定制和擴展,它在代碼重用、解耦和業(yè)務邏輯分離、性能優(yōu)化以及系統(tǒng)架構中起到了重要的作用,需要的朋友可以參考下
    2023-08-08
  • Java switch多值匹配操作詳解

    Java switch多值匹配操作詳解

    這篇文章主要介紹了Java switch多值匹配操作詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-01-01
  • 如何使用maven-helper插件解決jar包沖突問題

    如何使用maven-helper插件解決jar包沖突問題

    安裝了Maven?Helper插件,只要打開pom文件,就可以打開該pom文件的Dependency?Analyzer視圖,這篇文章主要介紹了使用maven-helper插件解決jar包沖突,需要的朋友可以參考下
    2024-05-05
  • Java通過JsApi方式實現(xiàn)微信支付

    Java通過JsApi方式實現(xiàn)微信支付

    本文講解了Java如何實現(xiàn)JsApi方式的微信支付,代碼內(nèi)容詳細,文章思路清晰,需要的朋友可以參考下
    2015-07-07
  • java獲取登錄者IP和登錄時間的兩種實現(xiàn)代碼詳解

    java獲取登錄者IP和登錄時間的兩種實現(xiàn)代碼詳解

    這篇文章主要介紹了java獲取登錄者IP和登錄時間的實現(xiàn)代碼,本文通過兩種結合實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-07-07

最新評論