Java Servlet 3.0 server push: Sending data multiple times using same AsyncContext

倖福魔咒の 提交于 2019-12-08 23:35:36

问题


Lead by several examples and questions answered here ( mainly http://www.javaworld.com/javaworld/jw-02-2009/jw-02-servlet3.html?page=3 ), I want to have server sending the response multiple times to a client without completing the request. When request times out, I create another one and so on.

I want to avoid long polling, since I have to recreate request every time I get the response. (and that quite isn't what async capabilities of servlet 3.0 are aiming at).

I have this on server side:

@WebServlet(urlPatterns = {"/home"}, name = "async", asyncSupported = true) 

public class CometServlet extends HttpServlet {

    public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException {

        AsyncContext ac = request.startAsync(request, response);

        HashMap<String, AsyncContext> store = AppContext.getInstance().getStore();

        store.put(request.getParameter("id"), ac);

    }
}

And a thread to write to async context.

class MyThread extends Thread {
    String id, message;

    public MyThread(String id, String message) {
        this.id = id;
        this.message = message;
    }

    public void run() {
        HashMap<String, AsyncContext> store = AppContext.getInstance().getStore();
        AsyncContext ac = store.get(id);
        try {
            ac.getResponse().getWriter().print(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

But when I make the request, data is sent only if I call ac.complete(). Without it request will always timeout. So basically I want to have data "streamed" before request is completed.

Just to make a note, I have tried this with Jetty 8 Continuation API, I also tried with printing to OutputStream instead of PrintWriter. I also tried flushBuffer() on response. Same thing.

What am I doing wrong?

Client side is done like this:

    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'http://localhost:8080/home', true);
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 3 || xhr.readyState == 4) {
            document.getElementById("dynamicContent").innerHTML = xhr.responseText;
        }
    }
    xhr.send(null);

Can someone at least confirm that server side is okay? :)


回答1:


Your server-side and client-side code is indeed ok. The problem is actually with your browser buffering text/plain responses from your web-server. This is the reason you dont see this issue when you use curl.

I took your client-side code and I was able to see incremental responses, with only just one little change:

response.setContentType("text/html");

The incremental responses showed up immediately regardless of their size.

Without that setting, when my output was a small message, it was considered as text/plain and wasnt showing up at the client immediately. When I kept adding more and more to the client responses, it got accumulated until the buffer size reached about 1024 bytes and then the whole thing showed up on the client side. After that point, however, the small increments showed up immediately (no more accumulation).




回答2:


I know this is a bit old, but you can just flushBuffer on the response as well.



来源:https://stackoverflow.com/questions/16788371/java-servlet-3-0-server-push-sending-data-multiple-times-using-same-asynccontex

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!