Create-react-app: [help wanted] Manually proxy settings to open connection with websocket.org

Created on 19 May 2017  路  9Comments  路  Source: facebook/create-react-app

Hey hi.

Since [email protected] and higher create-react-app support manual proxy settings.

After creating app like

creare-react-app proxy-test

I installed socket yarn add socket.io-client, added proxy settings to the package.json like:

  "proxy": {
    "/": {
      "target": "ws://echo.websocket.org",
      "ws": true
    }
  }

changed src/App.js:

import io from 'socket.io-client';

class App extends Component {
  constructor(props) {
    super(props);

    this.socket = io();
  }

  componentDidMount() {
    console.log('MOUNTED');
    this.socket.on('connect', () => console.log('Connected to the socket');
  }

But when I'm opening the console, I can see that request actually goes through HTTP and I'm getting 404 response, because there is no that page (this page exists only for web socket request)

Request URL: http://localhost:3000/socket.io/?EIO=3&transport=polling&t=LmXuie9
Request Method: GET
Status Code: 404 Not Found

Expected behavior:

Request URL: wss://localhost:3000/socket.io/?EIO=3&transport=polling&t=LmXuie9
Request Method: GET
Status Code: 101 Web Socket Protocol Handshake

When I'll resolve that, will open PR with an example in improved documentation.

question

Most helpful comment

UPDATE: Final words.

If you would like to connect WebSocket server that already hosted at ws://DOMAIN_URL like ws://echo.websocket.org - you can't use any client libraries like socket.io-client or ws.
You need to use native WebSockets in the browser

Also, you don't need to configure a proxy for that purpose.

The solution will be: After creating app like creare-react-app proxy-test, connect to WebSocket server in src/App.js:

class App extends Component {
  constructor(props) {
    super(props);

    this.socket = new WebSocket('ws://echo.websocket.org');
  }

  componentDidMount() {
    this.socket.onmessage = (message) => {
      const messageData = JSON.stringify(message);

      console.log(messageData);
    }

    // Give some time for socket to establish connection
    setTimeout(() => {
      this.socket.send('create-react-app');
    }, 3000);
  }

All 9 comments

@jamesblight Mind looking at this?

As I found out when I'm using web sockets, it is not necessary to turn on the proxy, because requests are going not through http/https, but through ws/wss (example: this.socket = new WebSocket('wss://echo.websocket.org/');), so there should not be issues with CORS.

But I'm still confused about: why after setting proxy to use sockets like:

  "target": "link",
  "ws": true

url for request generates like: Request URL: http://localhost:3000/ instead of Request URL: wss://localhost:3000/.

sockets.io-client propose to fix this issue, with next server and client configuration:
https://github.com/socketio/socket.io/issues/1942#issuecomment-299764672

Looks like that is not an issue of create-react-app, so will open the question at StackOverflow.

P.S: will keep that issue up to date after closing.

Thanks. If you find an answer please don鈥檛 hesitate to send a PR to our docs 馃槈

@YUzhva @gaearon I spent a bit of time investigating this issue. The proxy is working, but ws://echo.websocket.org is not running a socket.io server. This is why you're seeing a 404 response. If you use socket.io, you need to use a socket.io server.

If you look at the network requests with and without the proxy defined in package.json, you can see that the behaviour is slightly different. With proxy, there's a 404. Without, there's a 200 GET and then a 404 POST. You'll also see different behaviour if you proxy to the secure websocket (You get a 500 error):

 "proxy": {
    "/": {
      "target": "wss://echo.websocket.org",
      "ws": true,
      "secure": true
    }
  }

TLDR; socket.io client will only work with a socket.io server, and websocket.org doesn't support this.
https://github.com/socketio/socket.io/issues/533

If you want to proxy a websocket connection, you can use plain Websockets (without socket.io)
https://github.com/websockets/ws#echowebsocketorg-demo

If you want to use socket.io, you can run your own local socket.io server to connect to:

var app = require('http').createServer(handler)
var io = require('socket.io')(app);
var fs = require('fs');

app.listen(3001);

function handler (req, res) {
  res.writeHead(200);
  res.end('');
}

io.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('other', function (data) {
    console.log(data);
  });
});

Then, setup your proxy:

"proxy": {
  "/socket.io": {
    "target": "ws://localhost:3001"
    "ws": true
  }
}

@jamesblight Anything we could add to the docs?

@gaearon Not sure if you need to add this to create-react-app documentation because that mostly touches to other libs.

Is note like would be helpful?

NOTE: WebSocket libraries like socket.io or ws requires to run a live server instead of making requests by ws://DOMAIN_URL. Their clients (socket.io-client, ws.clinet) reference to a back end with the role of a client in the websocket communication.

Server rendering also would not help you, so you need to write both server and client by using thair libraries, OR you need to use native (pure JS) WebSocket object in your create-react-app.

@gaearon The docs cover a lot of areas not directly related to CRA, so it probably won't hurt to add some info on WebSockets. PR #2305

@jamesblight I added an extra note to your fork.

UPDATE: Final words.

If you would like to connect WebSocket server that already hosted at ws://DOMAIN_URL like ws://echo.websocket.org - you can't use any client libraries like socket.io-client or ws.
You need to use native WebSockets in the browser

Also, you don't need to configure a proxy for that purpose.

The solution will be: After creating app like creare-react-app proxy-test, connect to WebSocket server in src/App.js:

class App extends Component {
  constructor(props) {
    super(props);

    this.socket = new WebSocket('ws://echo.websocket.org');
  }

  componentDidMount() {
    this.socket.onmessage = (message) => {
      const messageData = JSON.stringify(message);

      console.log(messageData);
    }

    // Give some time for socket to establish connection
    setTimeout(() => {
      this.socket.send('create-react-app');
    }, 3000);
  }
Was this page helpful?
0 / 5 - 0 ratings