天天看點

Springmvc ModelAndView踩過的坑之HttpServletResponse response

先抛出問題。以下兩個方法聲明有毛差別:

這是在一個controller裡面的接口方法聲明,這兩個方法,一個聲明了

另一個沒有,他們看似沒有差別,但是spring mvc的套路裡面,他們在特殊場景下的差別大的你想哭。

先描述問題的源頭:

某天刮風,飄來了一個接口需要處理

http://localhost:8088/1/2/rg.html

這個接口沒有什麼特殊,get請求,傳回json資料,由于習慣使用g.html而不是g.json,再為了相容jsonp,然而依賴@responsebody注解的方式,對jsonp支援不夠完美。

是以,方法g裡面,直接操作response,具體處理的地方是另一個地方,利用filter+threadlocal實作的,是以,在g方法中無需聲明httpservletresponse就能達到目的

這樣處理一下,接口也的确傳回了資料,但是reponse.status一直是500。問題描述完畢。

怎麼了,你累了,說好的200呢?

首先找到500的原因.

spring mvc裡面,我配置了根據用戶端的不同的請求決定不同的view進行響應的視圖解析器

實驗證明,如果我不配置這個解析器,頁面會直接404,其實這是同一個問題,是以我去掉這個解析器,頁面立即顯示了閃花眼鏡的tomcat404

Springmvc ModelAndView踩過的坑之HttpServletResponse response

看到錯誤資訊,加上404,聯想到/1/2/1/2/rg這個資源沒有找到,然而,我們本也沒打算給它配資源,get請求回去的,是json資料。

在dispaterserlvet的方法dodispatch中,modelandview被指派,利用這個入口,可以找到原因。

循序打入斷點,到了解析方法參數的地方。

如果mv為null,則不會去尋找資源,是以開始尋找這個void請求,為毛還傳回不為null的mv。

往下走,

org.springframework.web.servlet.mvc.method.annotation.requestmappinghandleradapter.invokehandlermethod中,調用getmodelandview

如果

為真,那麼我們就達到目的了。(我為什麼會這麼推測了,是以controller參數含response和不含response的情況下,我分别跟蹤了代碼。為什麼想到需要response參數呢,因為别人家的接口都正确傳回了200狀态,我家的為什麼不按套路,隻有對比了。)

往下走

org.springframework.web.servlet.mvc.method.annotation.servletinvocablehandlermethod.invokeandhandle中的判斷條件

這是請求controller層接口的實作方法,由于我們的rg方法是void傳回類型,是以,這裡的returnvalue是null,如果滿足

就好,而帶response參數的請求

為true。

最終

handlermethodargumentresolver.resolveargument(parameter, mavcontainer, webrequest, binderfactory);

隐藏了我們想要的真相。

對于參數response,他對應的方法參數解析器是

mavcontainer是modelandview的容器,裡面存放了很多資訊,這裡不深究了。

這裡

設定了請求已經被處理的辨別,這樣

就為真了。

最後帶了response參數的方法,最終傳回的modelandview為null,也就不會找到資源

/1/2/1/2/rg

也就不會出現404了。

總結

httpservletresponse httpservletresponse參數神奇的原因是因為

它做了特殊處理,帶上這個參數的接口,都會被認為請求已經被處理了。

在springmvc裡面,一個參數聲明與否,并不是等價的,即使你沒有用到,他也有存在的意義

新部落格位址:http://www.cnblogs.com/windliu 

繼續閱讀