Jersey SSE client is not receiving events

2020-07-30 01:24发布

问题:

I have written a rudimentary Java application to consume SSE (server-sent events) streamed from a Node.js server, using the Jersey SSE client. However, I am unable to receive the events. To verify the server component is working as expected, I used the curl as follows:

curl -v -H "Accept: text/event-stream" http://localhost:8080/events/

I get the following response:

*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET /events/ HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: text/event-stream
> 
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Content-Type: text/event-stream
< Cache-Control: no-cache
< Connection: keep-alive
< Date: Wed, 26 Apr 2017 17:12:00 GMT
< Transfer-Encoding: chunked
< 

event: ping
data: 0.6637400726922664

event: ping
data: 0.8538157046725585

The code for my SSE client in Java is as follows (Java 8, Jersey Client 1.19.3, Jersey Media SSE 2.25.1):

import org.glassfish.jersey.media.sse.EventListener;
import org.glassfish.jersey.media.sse.EventSource;
import org.glassfish.jersey.media.sse.InboundEvent;
import org.glassfish.jersey.media.sse.SseFeature;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;

public class NodeCaptureSSE {

  public static void main(String[] args) {

    Client client = ClientBuilder.newBuilder().register(SseFeature.class).build();
    WebTarget target = client.target("http://localhost:8080/events/");
    EventSource eventSource = EventSource.target(target).build();
    EventListener listener = new EventListener() {
        @Override
        public void onEvent(InboundEvent inboundEvent) {
            System.out.println(inboundEvent.getName() + "; " + inboundEvent.readData(String.class));
        }
    };
    eventSource.register(listener, "ping");
    eventSource.open();
    System.out.println("Connected to SSE source...");
    try {
      Thread.sleep(25_000);
    }
    catch (InterruptedException ie) {
      System.err.println("Exception: " + ie.getMessage());
    }
    eventSource.close();
    System.out.println("Closed connection to SSE source");
  }
}

The only output I see on the screen is:

Connected to SSE source...

followed by an exit, after 25 seconds. Since the server is streaming named events ("ping"), I specified that while registering the listener to the event source. Omitting the second parameter to the eventSource.register(...); did not do anything, although I did not expect it to. I also removed the ending / in the URL, but that yields a 404 Not Found (as expected). I hope to get any pointers in the right direction.

回答1:

Your code worked fine for me. In fact I was looking desperately for this code so thanks ^_^ hahaha. Anyways, I have an SSE event-stream outputting time events and here is what my output looked like with your code (i changed ping to time-event to attach to my server).

 Connected to SSE source...
time-event; Time is Thu Jul 20 10:10:37 CDT 2017
time-event; Time is Thu Jul 20 10:10:41 CDT 2017

The problem is most likely with your event-stream and the URL you are using to point to it, not with your client-side java code. Another thing I noticed is that in your curl command I don't see a charset specification on there. Make sure your charset is set to UTF-8. Here is what my cmd output looks like:

Here is the code I am using to produce the stream.

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.ws.http.HTTPException;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.PasswordAuthentication;
import java.util.Calendar;



    @SuppressWarnings("java.io.IOException")
    @WebServlet("/SSEServlet")
    public class SSEServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
        private boolean cancel;

        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException {

            System.out.println("You just entered the doGetMethod");
            response.setContentType("text/event-stream");
            response.setCharacterEncoding("UTF-8");
            PrintWriter printWriter = null;
            response.getBufferSize();


            while(true){
                try{
                    System.out.println("You just entered the while loop");
                    double randomNumber = Math.random()*10000;
                    printWriter = response.getWriter();

                    printWriter.print("event: time-event" + "\n");
                    printWriter.print("data: " + "Time is " + Calendar.getInstance().getTime() + "\n\n");
                    response.flushBuffer();
                    Thread.sleep((long)randomNumber);

                } catch (IOException | InterruptedException e){
                    e.printStackTrace();
                    break;
                }
            }
            System.out.println("Connection was aborted");
        }
    }


回答2:

If your application is Spring Boot application, there is a compatibility issue with Jersey. You need to add another dependency org.glassfish.jersey.inject:jersey-hk2:2.26 to fix the problem.

See https://github.com/bmuschko/gradle-docker-plugin/issues/534 https://github.com/jersey/jersey/issues/3664

It seems like not only related to Gradle. In my case, my project is Maven and Spring Boot application, after adding this dependency, I immediately receive the event.