天天看點

解決getWriter() has already been called for this response異常

近期,檢視公司應用日志系統error錯誤資訊時,發現了大量的nested exception is java.lang.IllegalStateException: getWriter() has already been called for this response異常。這個錯誤以前見到過,也解決過。于是想着趁有點空閑,總結下該錯誤。如有不對,望各位多包容,歡迎交流。

一、應用日志檔案中的錯誤資訊

ERROR 

977

--- [io-

8686

-exec-

10

] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() 

for

servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: getWriter() has already been called 

for

this

response] with root cause

java.lang.IllegalStateException: getWriter() has already been called 

for

this

response

at org.apache.catalina.connector.Response.getOutputStream(Response.java:

575

) ~[tomcat-embed-core-

8.5

.

5

.jar:

8.5

.

5

]

  • 原因分析

IllegalStateException: getWriter() has already been called for this response

        從字面意思不難得出錯誤原因:HttpServletResponse中的PrintWriter已經被手動調用過了。是以當servlet執行到方法結果處理邏輯時,需要将傳回值輸出到writer中去,這時發現PrintWriter已經被調用過。于是servlet認為這是使用混亂的邏輯錯誤,于是抛出錯誤。

        根本原因:在Controller接口方法中,既手動調用PrintWriter向用戶端輸出内容,又設定了方法傳回值。導緻servlet需要兩次将結果通過PrintWriter輸出到用戶端,結果報錯。

@RequestMapping

(value=

"/checkGetWriterError"

, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)

@ResponseBody

public

ServiceResponse<String> checkGetWriterError(HttpServletResponse response) 

throws

Exception {

log.info(

"驗證接口既手動調用輸出流flush,又return 傳回值.造成異常!"

);

PrintWriter printWriter = response.getWriter();

printWriter.write(ServiceResponse.ok(

"來自printWriter的傳回值"

).toString());

printWriter.flush();

//沒有該句也是報一樣錯.

return

ServiceResponse.ok(

"成功了,恭喜你."

);

}

結果:程式正常傳回結果,控制台出現異常。

(傳回結果中編碼問題,不在本文讨論範圍,請忽略)

解決getWriter() has already been called for this response異常
  • 源碼佐證

解決getWriter() has already been called for this response異常

二、擴充驗證附驗證結果

  • 驗證PrintWriter輸出流flush,無傳回值

@RequestMapping

(value=

"/checkGetWriterError2"

, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)

@ResponseBody

public

void

checkGetWriterError2(HttpServletResponse response) 

throws

Exception {

log.info(

"驗證接口手動調用PrintWriter輸出流, 無return 傳回值. 接口正常執行無異常!"

);

PrintWriter printWriter = response.getWriter();

printWriter.write(ServiceResponse.ok(

"來自printWriter的傳回值"

).toString());

printWriter.flush();

}

結果:程式正常傳回結果,控制台無異常。

(傳回結果中編碼問題,不在本文讨論範圍,請忽略)

解決getWriter() has already been called for this response異常
  • 調用ServletOutputStream輸出流flush,  無傳回值

@RequestMapping

(value=

"/checkGetWriterError3"

, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)

@ResponseBody

public

void

checkGetWriterError3(HttpServletResponse response) 

throws

Exception {

log.info(

"驗證接口手動調用ServletOutputStream輸出流, 無return 傳回值. 接口正常執行無異常!"

);

ServletOutputStream output = response.getOutputStream();

output.write(ServiceResponse.ok(

"來自ServletOutputStream的傳回值"

).toString().getBytes());

output.flush();

}

結果:程式正常傳回結果,控制台無異常。

解決getWriter() has already been called for this response異常
  • 調用ServletOutputStream輸出流flush,又return 傳回值

@RequestMapping

(value=

"/checkGetWriterError4"

, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)

@ResponseBody

public

ServiceResponse<String> checkGetWriterError4(HttpServletResponse response) 

throws

Exception {

log.info(

"驗證接口手動調用ServletOutputStream輸出流, 又執行return 傳回值. 接口傳回異常!"

);

ServletOutputStream output = response.getOutputStream();

output.write(ServiceResponse.ok(

"來自ServletOutputStream的傳回值"

).toString().getBytes());

output.flush();

return

ServiceResponse.ok(

"來自return的傳回值."

);

}

結果:程式傳回結果不正常,控制台無異常。

不僅ServletOutputStream輸出流中的内容被發送到用戶端,而且方法傳回結果也輸出到用戶端。

解決getWriter() has already been called for this response異常

繼續閱讀