ServletResponse的java.lang.IllegalStateException错误


java.lang.IllegalStateException: STREAM
at org.eclipse.jetty.server.Response.getWriter(Response.java:707)


java.lang.IllegalStateException: WRITER
at org.eclipse.jetty.server.Response.getOutputStream(Response.java:681)

今天在写一个框架的时候遇到一个问题,记录一下,报错如上,查看javax.servlet.ServletResponse接口中的定义如下:

/**
* Returns a {@link ServletOutputStream} suitable for writing binary
* data in the response. The servlet container does not encode the
* binary data.

* <p> Calling flush() on the ServletOutputStream commits the response.

* Either this method or {@link #getWriter} may
* be called to write the body, not both.
*
* @return a {@link ServletOutputStream} for writing binary data
*
* @exception IllegalStateException if the <code>getWriter</code> method
* has been called on this response
*
* @exception IOException if an input or output exception occurred
*
* @see #getWriter
*
*/

public ServletOutputStream getOutputStream() throws IOException;


/**
* Returns a <code>PrintWriter</code> object that
* can send character text to the client.
* The <code>PrintWriter</code> uses the character
* encoding returned by {@link #getCharacterEncoding}.
* If the response's character encoding has not been
* specified as described in <code>getCharacterEncoding</code>
* (i.e., the method just returns the default value
* <code>ISO-8859-1</code>), <code>getWriter</code>
* updates it to <code>ISO-8859-1</code>.
* <p>Calling flush() on the <code>PrintWriter</code>
* commits the response.
* <p>Either this method or {@link #getOutputStream} may be called
* to write the body, not both.
*
*
* @return a <code>PrintWriter</code> object that
* can return character data to the client
*
* @exception UnsupportedEncodingException
* if the character encoding returned
* by <code>getCharacterEncoding</code> cannot be used
*
* @exception IllegalStateException
* if the <code>getOutputStream</code>
* method has already been called for this
* response object
*
* @exception IOException
* if an input or output exception occurred
*
* @see #getOutputStream
* @see #setCharacterEncoding
*
*/

public PrintWriter getWriter() throws IOException;

注意这两句:
Either this method or {@link #getWriter} may be called to write the body, not both.
Either this method or {@link #getOutputStream} may be called to write the body, not both.

再看jetty的源码,jetty.server.Response的源码:

public ServletOutputStream getOutputStream() throws IOException
{
if (_outputState!=NONE && _outputState!=STREAM)
throw new IllegalStateException("WRITER");

ServletOutputStream out = _connection.getOutputStream();
_outputState=STREAM;
return out;
}



public PrintWriter getWriter() throws IOException
{
if (_outputState!=NONE && _outputState!=WRITER)
throw new IllegalStateException("STREAM");

/* if there is no writer yet */
if (_writer==null)
{
/* get encoding from Content-Type header */
String encoding = _characterEncoding;

if (encoding==null)
{
/* implementation of educated defaults */
if(_cachedMimeType != null)
encoding = MimeTypes.getCharsetFromContentType(_cachedMimeType);

if (encoding==null)
encoding = StringUtil.__ISO_8859_1;

setCharacterEncoding(encoding);
}

/* construct Writer using correct encoding */
_writer = _connection.getPrintWriter(encoding);
}
_outputState=WRITER;
return _writer;
}

从源码的第3-4行可以得以验证,也就是说对于同一个response实例你只能使用其中的一个方法,不能两者混用。
### Jakarta Servlet中关于HttpServletResponse构造函数的IllegalStateException问题分析 在Java中,`jakarta.servlet.http.HttpServletResponse` 是一个接口,而不是一个具体的类[^1]。因此,尝试直接实例化该接口会导致 `java.lang.IllegalStateException` 或其他相关异常,因为接口本身无法被实例化。通常情况下,这种错误可能出现在使用依赖注入框架(如Spring)时,框架未能正确提供实现类的实例。 以下是可能导致此问题的原因及解决方案: #### 1. 接口与实现类的区别 `jakarta.servlet.http.HttpServletResponse` 是一个标准的Servlet API接口,定义了HTTP响应的行为。实际的实现类由Servlet容器(如TomcatJetty等)提供[^2]。如果代码中试图通过 `new HttpServletResponse()` 的方式实例化接口,就会抛出 `IllegalStateException` 异常。 #### 2. 框架依赖注入问题 在现代Web开发中,尤其是基于Spring的应用程序,`HttpServletResponse` 对象通常通过依赖注入或方法参数传递的方式获取。如果框架配置不正确或未正确注册组件,可能会导致无法找到合适的构造函数,从而引发异常。 #### 解决方案 - **确保正确的依赖注入** 在Spring MVC中,可以通过控制器方法的参数列表自动注入 `HttpServletResponse` 实例。例如: ```java @GetMapping("/example") public void handleRequest(HttpServletResponse response) { // 使用response对象 } ``` - **检查Servlet容器版本** 确保使用的Servlet容器(如Tomcat)支持Jakarta EE 9及以上版本,并且项目中引入的依赖库版本一致。例如,Maven中的依赖应如下配置: ```xml <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>5.0.0</version> <scope>provided</scope> </dependency> ``` - **避免直接实例化接口** 不应尝试直接实例化 `HttpServletResponse`,而应依赖Servlet容器提供的实现类。如果需要自定义行为,可以创建包装类(Wrapper),继承 `jakarta.servlet.http.HttpServletResponseWrapper`。 #### 示例:自定义Response包装类 以下是一个简单的 `HttpServletResponse` 包装类示例: ```java import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponseWrapper; public class CustomResponseWrapper extends HttpServletResponseWrapper { public CustomResponseWrapper(HttpServletResponse response) { super(response); } @Override public void addHeader(String name, String value) { // 自定义逻辑 super.addHeader(name, value); } } ``` 通过这种方式,可以在不直接实例化接口的情况下扩展功能[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值