servlet异步处理中遇到一些问题及其分析

本文详细介绍了使用Servlet进行异步处理的方法及注意事项,包括如何避免非法调用asyncComplete()的问题,以及确保请求支持异步操作的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

刚开始学习servlet,照着书写了写异步处理的一些例子:

 

@WebServlet(urlPatterns="/async", asyncSupported = true)
public class AsyncServlet extends HttpServlet {
	@Override
	public void service(HttpServletRequest request, HttpServletResponse response) 
			throws IOException, ServletException{
		response.setContentType("text/html; charset = utf-8");
		PrintWriter out = response.getWriter();
		out.println("<title>异步调用测试</title>");
		out.println("进入servlet的时间为:" + new Date() + "<br/>");
		out.flush();
		//创建AsyncContext,开始异步调用
		boolean isasync = request.isAsyncSupported();
		AsyncContext actx = request.startAsync();
		actx.setTimeout(20000);
		Runnable run = new Executer(actx);
		actx.start(new Executer(actx));
		out.println("结束servlet的时间为: " + new Date() + "<br/>");
		out.flush();
	}
}

 

public class Executer implements Runnable{
	private AsyncContext actx = null;
	public Executer(AsyncContext actx){
		this.actx = actx;
	}
	public void run(){
		try{
			Thread.sleep(5000);
			ServletRequest request = actx.getRequest();
			List<String> books = new ArrayList<String>();
			books.add("java学习");
			books.add("javaee 学习");
			request.setAttribute("books", books);
			actx.dispatch("/async.jsp");
		}
		catch(Exception e){
			e.printStackTrace();
		}
	}
}

 

 <body>
    <%
    List<String> books = (List<String>)request.getAttribute("books");
    if(books !=null){
    	for(String book: books){
    		out.println(book);
    		out.println("<br/>");
    	}
    }
    out.println("业务调用时间结束:"+ new Date() + "<br/>");
    request.getAsyncContext().complete();
    %>
  </body>

 先是报了一个这样的错误:

 

 

严重: Servlet.service() for servlet [webDemo.AsyncServlet] in context with path [/webDemo] threw exception [javax.servlet.ServletException: java.lang.IllegalStateException: Cannot create a session after the response has been committed] with root cause
java.lang.IllegalStateException: Cannot create a session after the response has been committed
	at org.apache.catalina.connector.Request.doGetSession(Request.java:2924)
	at org.apache.catalina.connector.Request.getSession(Request.java:2300)
	at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:897)
	at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:229)
	at org.apache.catalina.core.ApplicationHttpRequest.getSession(ApplicationHttpRequest.java:569)

 即:不能在响应提交后,再创建session,分析出现这个问题的原因是由于我们的代码中存在以下语句:

 

response.setContentType("text/html; charset = utf-8");

响应向客户端返回来了http的头文件,导致了不能创建sessionid,因为sessionid一般存在于http cookie

的头文件了,所以为了避免以上问题,我们可以在上面的语句加上一句:

 

HttpSession session = request.getSession();

 先创建session,当然也可以不通过response输出头文件。

 

在解决了这个问题之后程序依然报错

严重: Servlet.service() for servlet [webDemo.AsyncServlet] in context with path [/webDemo] threw exception [java.lang.IllegalStateException: Calling [asyncComplete()] is not valid for a request with Async state [DISPATCHED]] with root cause
java.lang.IllegalStateException: Calling [asyncComplete()] is not valid for a request with Async state [DISPATCHED]
	at org.apache.coyote.AsyncStateMachine.asyncComplete(AsyncStateMachine.java:227)
	at org.apache.coyote.http11.Http11AprProcessor.actionInternal(Http11AprProcessor.java:456)
	at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:867)
	at org.apache.coyote.Request.action(Request.java:344)
	at org.apache.catalina.core.AsyncContextImpl.complete(AsyncContextImpl.java:91)
	at org.apache.jsp.async_jsp._jspService(async_jsp.java:92)
	at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)

 即:对于处于dispatched异步状态下的request调用asyncComplete()是无效的,分析可知问题出在以下语句:

request.getAsyncContext().complete();

我们删除这条语句,问题解决。

我们在api中关于complete函数找到了以下几句话:

It is legal to call this method any time after a call to ServletRequest.startAsync() or ServletRequest.startAsync(ServletRequest, ServletResponse), and before a call to one of the dispatch methods of this class.

说的很清楚在startAsync之后以及在dispatch方法之前调用是合法的。

在关于dispatch方法的说明中:

There can be at most one asynchronous dispatch operation per asynchronous cycle, which is started by a call to one of the ServletRequest.startAsync() methods. Any attempt to perform an additional asynchronous dispatch operation within the same asynchronous cycle will result in an IllegalStateException. If startAsync is subsequently called on the dispatched request, then any of the dispatch or complete() methods may be called.

在使用了dispatch方法之后只有startAsync方法调用后才能调用complete方法。

 

最后应当注意的是,在使用异步之前最好查看下request是否支持异步操作,即查看boolean isAsyncSupported()

 

Asynchronous operation is disabled for this request if this request is within the scope of a filter or servlet that has not been annotated or flagged in the deployment descriptor as being able to support asynchronous handling.

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值