国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 解決偶現的MissingServletRequestParameterException異常問題

解決偶現的MissingServletRequestParameterException異常問題

2022-02-28 00:34Mr_SeaTurtle_ Java教程

這篇文章主要介紹了解決偶現的MissingServletRequestParameterException問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

概述

最近遇到一個偶現的問題,在向服務端請求的時候,偶爾會出現異常,在請求中的query String 傳遞了參數,卻出現了異常MissingServletRequestParameterException

如下所示:

018-02-05 11:29:34.910 ERROR 41469 --- [a626f375-7f79-4fd2-88be-1db10a3811cb-] [nio-8080-exec-7] c.s.s.f.ValidationGlobalExceptionHandler : org.springframework.web.bind.MissingServletRequestParameterException: Required long parameter 'xxx' is not present
  at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:198)
  at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:109)
  at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
  at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:158)
  at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)
  at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
  at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
  at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
  at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
  at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
  at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
  at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
  at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
  at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)

在請求中顯然是帶了這個參數的,開始時還以為自己眼花,于是又試了一下,結果接口返回又正常了。

但是,既然錯誤日志出現了,就不能輕易地放過,尤其是這種偶現的錯誤,充滿著風險,極有可能在某個關鍵時刻爆發。因此決定抽出時間排查這個問題。接下來,就是整個排查過程。

 

排查過程

具體的請求如下所示:

curl -X GET --header "Accept: */*" http://localhost:8080/xxx/api/v3/xxx/getXX?param=123456

其中param在Controller的方法中被聲明為required=true,也就是必傳參數,而在前后端交互里,這個參數也是一定會傳的。

既然這是一個偶現的問題,就不可能通過手動一次次地調用請求進行問題的重現。在這里我采用了Jmeter作為請求觸發器,進行30次一批的重復請求,結果在跑第一次的時候,就出現了一次請求異常。

反復跑了兩三次之后,都出現了同樣的結果,既然問題已經確認,并且能夠穩定重現,接下來就是如何找到問題的根源并解決這個問題了。

因為有具體的異常類,所以我的第一想法就是在這個異常類的構造函數中加斷點,看看為什么會拋出這個異常。通過調用棧,在RequestParamMethodArgumentResolver(AbstractNamedValueMethodArgumentResolver)中發現如下代碼片段

      Object arg = resolveName(resolvedName.toString(), nestedParameter, webRequest); //在RequestParamMethodArgumentResolver中,直接通過調用request.getParameterValues(name)來獲取普通請求的參數
      if (arg == null) {
          if (namedValueInfo.defaultValue != null) {
              arg = resolveStringValue(namedValueInfo.defaultValue);
          }
          else if (namedValueInfo.required && !nestedParameter.isOptional()) {
              handleMissingValue(namedValueInfo.name, nestedParameter, webRequest); //如果沒有獲取到且沒有默認值,就會在這里拋出異常。
          }
          arg = handleNullValue(namedValueInfo.name, arg, nestedParameter.getNestedParameterType());
      }
      else if ("".equals(arg) && namedValueInfo.defaultValue != null) {
          arg = resolveStringValue(namedValueInfo.defaultValue);
      }

看到這里的時候心里不禁疑惑,難道真的沒傳參數?或者是參數在傳遞的過程丟了?或者…被框架吃了?!

但疑惑不是我想要的,答案才是我想要的。既然request.getParameterValues里面沒有得到想要的值,那就應該去找正常請求時,這個值是如何被設置的。

首先想到的是查看Request的類圖結構。以及請求被處理的流程圖

解決偶現的MissingServletRequestParameterException異常問題

解決偶現的MissingServletRequestParameterException異常問題

所以,最原始的數據被保存在了org.apache.coyote.Request這個類中,深入這個類,我們就能夠更接近答案。于是直接到了Http11Processor的service方法中,看具體的處理過程。首先在799行加斷點,看看是處理結果是什么,由于問題是處在parameter上,直接查看此時request中parameters的各種值。

正常請求:

解決偶現的MissingServletRequestParameterException異常問題

異常請求:

解決偶現的MissingServletRequestParameterException異常問題

對比兩者不難發現,異常請求中的queryMB與正常請求中的是一樣的,也就是說我們請求中帶的參數被傳遞到了服務器。但異常請求didQueryParameters被置成了true,而從代碼中可以知道,這個代碼實際上是用于判斷query string是否已經被解析過了,并且,在請求處理結束的時候,會調用parameter的recycle方法

  public void recycle() {
      parameterCount = 0;
      paramHashValues.clear(); //清空了解析后的parameter map
      didQueryParameters=false; //是否被解析過,置成false
      encoding=null;
      decodedQuery.recycle();
      parseFailedReason = null;
  }

由于Tomcat中,Request以及Response對象都是會被循環使用的,因此這個時候也是整個Request被重置的時候。

所以根本原因是,在Parameter被重置了之后,didQueryParameters又被置成了true,導致新的請求參數沒有被正確解析,就報錯了(此時的parameterMap已經被重置,為空)。

而didQueryParameters只有在一種情況下才會被置為true,也就是handleQueryParameters方法被調用時。

而handleQueryParameters會在多個場景中被調用,其中一個就是getParameterValues,獲取請求參數的值。

到這里,就可以推斷,應用中可能存在代碼,在請求結束之后,仍然通過Request對象獲取其中的參數值。

全局搜索引用了HttpServletRequest的地方。最終發現埋點類中有如下代碼

@Async
  public void buryPoint(long userId, HttpServletRequest request.....) {
      if (request != null) {
         xxx = request.getParameter("xxx");
      }

由于這段邏輯是異步執行的,因此完全有可能在請求結束之后,仍然調用request.getParameter方法,導致下一次的請求參數不被解析。將此段代碼注釋掉,重新使用Jmeter進行請求,錯誤不再出現。

 

結論

不要將HttpServletRequest傳遞到任何異步方法中!

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/Mr_SeaTurtle_/article/details/79274748

延伸 · 閱讀

精彩推薦
  • Java教程使用springboot activiti關閉驗證自動部署方式

    使用springboot activiti關閉驗證自動部署方式

    這篇文章主要介紹了使用springboot activiti關閉驗證自動部署方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教...

    poyi20083582021-12-28
  • Java教程java異常(Exception)處理機制詳解

    java異常(Exception)處理機制詳解

    這篇文章主要介紹了java異常(Exception)處理機制詳解的相關資料,主要介紹異常的定義及使用方法,需要的朋友可以參考下...

    Java教程網3832020-08-28
  • Java教程Java進階:用匿名內部類實現 Java 同步回調

    Java進階:用匿名內部類實現 Java 同步回調

    在一個應用系統中,不論使用何種編程語言,模塊之間要進行調用,僅存在三種方式:同步調用、異步調用、回調。本文就其中回調方式進行詳細解讀,并...

    小z同學6792020-10-30
  • Java教程Java五子棋AI實現代碼

    Java五子棋AI實現代碼

    今天小編就為大家分享一篇關于Java五子棋AI實現代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    凌晨兩點半的太陽6452021-07-14
  • Java教程Java游戲服務器之數據庫表存取封裝

    Java游戲服務器之數據庫表存取封裝

    這篇文章主要介紹了Java游戲服務器之數據庫表存取封裝的相關資料,需要的朋友可以參考下 ...

    Metazion2212020-03-06
  • Java教程Spring Boot之@Async異步線程池示例詳解

    Spring Boot之@Async異步線程池示例詳解

    在Spring Boot中,我們只需要通過使用@Async注解就能簡單的將原來的同步函數變為異步函數,下面這篇文章主要給大家介紹了關于Spring Boot之@Async異步線程池的相...

    hguisu10642022-01-03
  • Java教程Mybatis中注解@MapKey的使用詳解

    Mybatis中注解@MapKey的使用詳解

    mybatis的原身是ibatis,現在已經脫離了apache基金會。這篇文章主要介紹了Mybatis中注解@MapKey的使用的相關資料,需要的朋友可以參考下...

    mrr6052020-06-27
  • Java教程Java程序員應該遵守的10條紀律

    Java程序員應該遵守的10條紀律

    Java程序員有許多應遵循的守則或最佳實踐方式。本文概述了每個開發者最應該遵循的10條守則或戒律,如果不遵循它們,將會導致災難性后果。 ...

    lijiao5222020-01-05
主站蜘蛛池模板: 91精品国产综合久久久久久 | 日日躁夜夜躁狠狠躁 | 亚洲激情综合 | 日韩免费一区 | 日韩成人在线视频 | 中文字幕免费 | 一区二区视频 | 天天天操 | 国产欧美日韩一区二区三区 | 免费看亚洲 | 精品久久99| 国产干干干 | 国产区在线观看 | 性色浪潮 | 这里只有国产精品 | 中文字幕一区在线 | 免费成人在线电影 | 日韩中文字幕在线 | 狼人综合av | 91精品国产综合久久香蕉 | 精品在线播放 | 成人在线免费观看视频 | 欧美成人一级 | 国产资源视频在线观看 | 久久一区二区三 | 欧美影院日韩 | 久久a毛片| 日韩三级电影在线观看 | 久久国产午夜 | 亚洲 欧美 日韩在线 | 久久久久无码国产精品一区 | 91久久久久久久久久 | 亚洲精品一区中文字幕乱码 | 免费一级性片 | 激情国产| 成人在线视频免费观看 | 国内久久久久久 | 欧美日韩一 | 免费观看电视在线高清视频 | 天堂v视频| 久操视频在线 |