我在理解异步servlet如何工作方面遇到了问题,一般来说,servlet如何将响应传递给客户端 我想要做的是通过ajax将视频上传到servlet。我认为使用异步servlet,我会立即在浏览器中获得响应,然后长任务将在另一个线程中完成。
我在这里发布我的初始代码,在为文件进程编写任何代码之前,只是一个测试异步的初始servlet。
@WebServlet(name = "VideoUploader", urlPatterns = {"/VideoUploader"},
asyncSupported = true)
@MultipartConfig
public class VideoUploader extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
final PrintWriter pw = response.getWriter();
final AsyncContext ac = request.startAsync();
ac.setTimeout(80000);
ac.addListener(new AsyncListener() {
@Override
public void onComplete(AsyncEvent event) throws IOException {
System.out.println("On complete");
}
@Override
public void onTimeout(AsyncEvent event) throws IOException {
System.out.println("On timeout");
}
@Override
public void onError(AsyncEvent event) throws IOException {
System.out.println("On error");
}
@Override
public void onStartAsync(AsyncEvent event) throws IOException {
System.out.println("On start async");
}
});
ac.start(new Runnable() {
@Override
public void run() {
for (int i = 0; i <= 10; i++) {
System.out.println("Async task: "
+ Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
ac.complete();
}
});
pw.write("end");
pw.close();
}
}
然后,客户端部分是:
<form id="formVideo">
<label for="videoFile">Vídeo:</label>
<input id="videoFile" name="videoFile" type="file" /> <br/>
<input id="uploadVideoBtn" type="button" value="Subir" onClick="uploadVideo();"/>
</form>
<div id="notificaciones"/>
<script type="text/javascript">
function uploadVideo() {
var file = document.getElementById("videoFile").files[0];
var formdata = new FormData();
formdata.append("file", file);
var xhr = new XMLHttpRequest();
xhr.open("POST","/webapp/VideoUploader", true);
xhr.send(formdata);
xhr.onload = function(e) {
if (this.status == 200) {
alert(this.responseText);
}
};
}
</script>
当我没有将视频附加到文件输入时,过程按照我的预期完成,响应立即在浏览器中收到。但是当我附加任何大小的文件时,我的浏览器在另一个线程结束之前不会收到响应。
我正在研究非阻塞IO,但我不确定它是否与此行为有关。
我仍然不确定我是如何实现这一点的,虽然我会听取任何建议,但我想要了解这个异步servlet的行为。
答案 0 :(得分:2)
很明显,您的浏览器将等到另一个线程完成。
涉及以下步骤
只有在步骤6,响应才会返回给客户。因此,从客户的角度来看,普通请求和“asyncSupported = true
”之间没有区别。
Servlet 3.0通过使用“asyncSupported = true
”代替每个连接的线程来支持每个请求的线程。
每个连接的线程将导致线程饥饿。
@WebServlet(name = "VideoUploader", urlPatterns = { "/VideoUploader" }, asyncSupported = true)
@MultipartConfig
public class VideoUploader extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
final AsyncContext ac = request.startAsync();
ac.setTimeout(80000);
ac.addListener(new AsyncListener() {
public void onComplete(AsyncEvent event) throws IOException {
System.out.println("On complete");
}
public void onTimeout(AsyncEvent event) throws IOException {
System.out.println("On timeout");
}
public void onError(AsyncEvent event) throws IOException {
System.out.println("On error");
}
public void onStartAsync(AsyncEvent event) throws IOException {
System.out.println("On start async");
}
});
ac.start(new Runnable() {
public void run() {
System.out.println("Async task: "
+ Thread.currentThread().getName());
try {
for (Part part : ((HttpServletRequest) ac.getRequest())
.getParts()) {
System.out.println("File received"); // You Should write
// file here
// like
// part.write("fileName");
}
} catch (IOException e1) {
e1.printStackTrace();
} catch (ServletException e1) {
e1.printStackTrace();
}
ac.complete();
PrintWriter pw = null;
try {
pw = ac.getResponse().getWriter();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
pw.write("end");
pw.close();
}
});
}
}
答案 1 :(得分:1)
异步servlet将长时间运行的服务器端作业移交给其他服务器线程。非阻塞IO是servlet 3.1中的一项新功能,它处理传入数据阻塞或流速低于服务器可读取的情况。两者都是避免servlet线程饥饿的解决方案。他们不是要立即回复客户。
由于您使用的是Ajax,而不是常规的浏览器文件上载,如果您不关心servlet线程饥饿,它应该可以在Ajax端轻松实现甚至是同步servlet。 Ajax本质上是异步的。这是一个示例教程
http://www.javabeat.net/asynchronous-file-upload-using-ajax-jquery-progress-bar-and-java/