0

I am converting an existing production application from jquery to react.js. The backend is written in Java (spring boot). The existing app uses Server-Sent Events to push certain types of notifications from the server backend to the web clients. The existing production app works fine.

For the UI rewrite, I'm using react.js made with CRA (Create React App) port 3000 and default proxy through to my spring boot server on the same machine running on port 7001 all in development environment.

From React, the EventSource is getting instantiated and the request is passing through over to the spring boot server. It is registering the user and everything looks OK. When a notification message is to be sent from springboot to react I see the onopen() message handler called in React and the readyState transitions from 0 (pending) to 1 (open). And then nothing happens. on-message handler is never called. There are no errors in the javascript console, or on the springboot server backend (even with DEBUG level enabled for all packages). I don't see any errors in the browser Network tab (Firefox in this case). In another browser I have one of the old jquery clients running and it does get the message.

 "proxy": "https://localhost:7001",
  "private": true,
  "dependencies": {
    "@ant-design/icons": "^5.0.1",
    "@reduxjs/toolkit": "^1.9.4",
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^14.0.0",
    "@testing-library/user-event": "^14.4.3",
    "antd": "^5.4.2",
    "antd-mobile": "^5.29.1",
    "antd-mobile-icons": "^0.3.0",
    "axios": "^1.3.5",
    "bounce.js": "^0.8.2",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-redux": "^8.0.5",
    "react-router-dom": "^6.10.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^3.3.1"
  },

Code snippet from react functional component:

   const eventSource = new EventSource("/api/register/39/event/944?registrationCode=MDB");

   console.log(`DEBUG: eventSource.readyState=${eventSource.readyState}`);


   useEffect(() => {
      console.log(`DEBUG: useEffect| eventSource.readyState=${eventSource.readyState}`);

      eventSource.onopen = (e) => {
         console.log("DEBUG: eventSource connection open!",e);
         console.log(`DEBUG: onopen | eventSource.readyState=${eventSource.readyState}`);
      };

      eventSource.onerror = (e) => {
         if (e.readyState === EventSource.CLOSED) {
            console.log("DEBUG: eventSource connection CLOSED! Trying to reconnect!");
         }
      };

      eventSource.onmessage = (event) => {
         console.log("DEBUG: onmessage received! result=",event.data);
      };

      // return function cleanup() {
      //    console.log(
      //       `DEBUG: EventSourceController.cleanup() called.  Closing open stream.`
      //    );
      //    eventSource.close();
      // };

      //[eventSource]      
   });

I've searched the web to see if there is any funny business to be looking for when it comes to SSE and React, but nothing jumps out.

There is this similar unanswered question here but I don't have enough reputation points to up-vote it or even provide a comment.

I have no reason to believe that the message-type is being overwritten on the backend as this post suggests, as I am using the same message handler in the old jquery app and it is able to receive the messages without any issue.

jn4
  • 25
  • 6
  • 1
    Bumping this question again to see if anyone else has an answer. The client app does not appear to be getting the response unless (on the spring boot backend) emitter.complete() is called. Other web clients are receiving the message without the emitter.complete() call. – jn4 Jun 16 '23 at 19:48

1 Answers1

0

Can you show examples of data sent from server?

Are you sure that event field (in sent messages) is empty, non existent or equals message?

eventSource.onmessage is called only when client (browser) recieved event with undefined or message type.

  • Do you have a suggestion for how to monitor what is being sent using the client browser tools? I looked at Firefox and Chrome Network tab but don't see anything for these async messages. I can try to force the backend to dump something, but there are libraries in the way, so I'll have to see if I can figure that out also. – jn4 Apr 25 '23 at 13:49
  • for example: In Google Chrome / Chromium open "**Network**" - refresh page - switch to "All" or "**Fetch/XHR**" filter and look up connection to stream url, click on it, and select "**EventStream**" and you will see all incomminng messages / events with their id, type (event) and time. Also you can just open stream url in browser tab like any other page, and you'll everything that server is sending to client in the event stream. SSE is very simple and convient protocol for debugging – Alex Chernykh Apr 26 '23 at 16:23
  • Thanks I'll give that a try in a couple of days when I'm back in town. – jn4 Apr 26 '23 at 17:14
  • I've tried the following browsers: Chrome, Firefox, Brave (chromium). Firefox doesn't show EventSource in their devtools. Chrome and Brave show the EventSource tab but never show any data. Chrome and Brave only show the EventSource tab only after I send a message from the server (when the open is received), but no messages. I'm fairly certain that the backend is using the default "message" type because in my old jquery client version, the handler code looks like this: `eventSource.onmessage = event => { /*...*/ }` and it works, with no custom listener types. – jn4 Apr 28 '23 at 14:22
  • Here is a log output statement from the backend: `processMessageForEmitter: message={eventId=944, messageHTML=, action=message, threads=null, hasAttachedImage=false}` – jn4 Apr 28 '23 at 14:45
  • The spring boot SseEmitter API seems a little weird. It seems that I have to call `emmitter.complete();` after each message in order to get the message to send. Otherwise they never arrive at the client. And when I do call `emitter.complete();` it also seems to close the socket connection, because right after the message is received, the onclose() handle is fired, and the client cannot receive any further messages until a new EventSource() is created. This doesn't seem right. – jn4 Apr 28 '23 at 20:29
  • Yes, it's very weird situation, and it's really seams to me that the problem (ot some tricks) on backend side. BTW: can you directly open event stream URL? `/api/register/39/event/944?registrationCode=MDB` ? is there anything at all? – Alex Chernykh Apr 29 '23 at 19:13
  • Yes it does. The message looks like the one above with escaped \" double quotes: `data:{"......` – jn4 Apr 30 '23 at 23:49