1. 程式人生 > >常見踩坑案例(二)-Request method 'POST' not supported

常見踩坑案例(二)-Request method 'POST' not supported

一 前言

  最近涉及到與前後端的資料對接,按道理來說沒一點壓力結果被一前端童鞋帶坑裡去了(不過也是很久沒寫過這種前後端分離進行聯調的事情了,如果是一個人全套弄的話就不會出現下面問題)。

二 Request method 'POST' not supported 

  進入正文,跟前端進行資料聯調時,別人聯調都正常,到聯調我的介面(進行資料獲取)就出現了問題。

  下面進行異常場景還原(後端環境:Spring MVC4.0.5):

  1、前端訪問我這邊的介面丟擲錯誤碼:405 Method not allowed當時就感覺奇怪,我自己用postman都能調通啊,為什麼你那邊不能允許訪問呢。看到這個錯誤碼,於是我就丟擲兩個問題給他:

  • 你是用post請求嗎?
  • 你請求的context-type是json嗎?            

  然後他毫不猶豫的說都是。  2、於是我看下後端請求的日誌,SpringMVC日誌提示[org.springframework.web.servlet.PageNotFound] >>> Request method 'POST' not supported” 。 

  提示這個錯誤,我就納悶了。條件反射讓我想起是不是在@RequestMapping中Method 沒有指定為post? 其實我指定了post方法的,這個肯定排除了。

    @RequestMapping(value = "/home/test", method = RequestMethod.POST)
    @ResponseBody
    public Object test(@RequestBody UserEntity userEntity) {

        return "1234";
    }

  難道真的是我後端的問題?查了網上很多問題一堆不靠譜:(,一直沉迷於Request method 'POST' not supported這個資訊無法自拔,難道這配置不支援post方法?。於是就嘗試了以下手段:

  a、ResourceHttpRequestHandler

在springMVC配置檔案配置強制支援post方法。可想而知,ResourceHttpRequestHandler針對靜態資源的獲取及其快取設定。很明顯不符合場景,試了也是白試。如果你這種場景請參考這裡獲取對你有幫助:https://stackoverflow.com/questions/15588001/spring-not-accept-post-request-under-mvcresources-how-to-fix-that。

  b、嘗試將RequestMapping中請求的方法改成get,前端也用get請求,並沒有用。

  3、嘗試了上面方法後無果,有位前輩說不妨你跟蹤下SpringMVC中日誌程式碼

  第一步:檢視PageNotFound是否存在對應的類(這一步其實一出現我就檢視是沒有的),怎麼驗證它是否存在呢?很簡單:在程式碼中輸入它看是否有對應的引用包。

      

  第二步:第一步最直接的入口失敗,於是想到了SpringMVC的核心Servlet:DispatcherServlet, 而它的核心方法則是:doDispatch,於是在方法中進行斷點除錯找到出錯原因。經過除錯後,終於發現問題所在,發現在解析json是實體的屬性出錯,如下圖:

  上述案例是說不能解析namqe這個屬性,而我UserEntity物件中的屬性是name,所以解析類就丟擲異常(至於在哪一步解析出錯,這就不一一說了)。

  經過上面一步一步的探索終於找到問題的所在:原來是前端童鞋傳json的時候,把引數名稱弄錯了。

  4、拓展

雖然問題解決了,但是為啥Spring MVC 為啥丟擲那樣的日誌,而不是具體的錯誤資訊呢?如果是具體的錯誤資訊那不簡單明瞭嘛,也不至於花了這麼時間去定位問題所在。於是繼續除錯看看這個錯誤資訊為什麼被轉換了?看上面圖的971行,最終結果都會進入到這個方法processDispatchResult,而它的第一步就是檢測是否有異常,如果有異常則先處理異常:

  裡面流程也不一一顯示了,直接跳到具體解析異常的類:DefaultHandlerExceptionResolver,我們看看這個類中有什麼又是怎麼處理異常的。  

  看到上圖就應該想到之前提示的日誌為什麼有[org.springframework.web.servlet.PageNotFound],而找不到對應的類了吧,因為它只是一個日誌的Event_Name。

  繼續跟蹤:最終它是走入了HttpMessageNotReadableException類,表示讀取資訊錯誤。

  繼續進入handleHttpMessageNotReadable方法,看到這裡就知道結果了,它把原來的錯誤資訊給修改並返回了。

  另外這裡不是真的返回資訊,上面錯誤資訊返回之後還會再次進入DispatcherServlet類重新又走了一遍,所以錯誤資訊又重新判斷一次最終進入了下面這個方法,真正的輸入日誌的地方在這:

   所以這個是Spring MVC 4.0.5.RELEASE版本的問題,升級到4.2.0以上就不會丟擲這個問題,它會識別能識別的引數繼續執行,不會丟擲錯誤。

三 總結

針對這種405錯誤,總結一下幾點:

1、首先第一個需要確認請求方法型別是否一致?

2、請求資料型別 和 接收的資料型別是否一致?

3、請求引數是否正確?

以上都正確的話,然後在具體問題具體分析,一步一步跟蹤才是最有效的。  

遇上問題要冷靜,盲目從醫只會浪費時間,需要對症下藥,一步一步來。