Request delay when accessing proxied server from Chrome - node.js

I am using Vue.js's API proxying functionality (which internally uses http-proxy-middleware/http-proxy) to forward API requests to my localbackend server. I set it in vue.conf.js like so:
module.exports = {
devServer: {
port: 8081,
proxy: {
'/api': {
target: 'http://localhost:8080',
xfwd: false
}
}
}
}
For some weird reason though, about every other proxied request coming from Chrome is slow:
When a slow request is profiled in Chrome, it looks like below:
Any idea what might be causing this delay between fetchStart and requestStart? When accessing the proxy through 127.0.0.1, the problem goes away for some reason (DNS issues???). Checked the backend, and it responds correctly as well. The problem doesn't exist on Firefox either.
System is latest Win10, checked on stable and canary Chrome.

Related

Howto re-route webpack hot reload client?

I have an application created with create-react-app and typescript. This application is an oauth2 client, and it needs a valid redirect_uri with https. It also uses websockets. I could setup an nginx server that accepts https and wss connections, and forwards them to my development machine.
This is how it should work:
web browser --> https and wss request --> nginx --> ssh tunnel (remoteforward) --> development machine --> local webpack and local application server
Nginx maps all https requests to localhost:3000 and all wss requests (anything under /api) to localhost:9091. These are forwarded to the local development machine via ssh tunnels. The local dev machine runs webpack on port 3000 and an appserver on port 9091.
This allows me to develop a valid web based oauth2 client, with valid https certificates and redirect_uri values. This setup was working for a long time. Today I have updated all packages (including node js, create-react app and webpack), and it stopped working. Here is the trace log:
SecurityError: Failed to construct 'WebSocket': An insecure WebSocket connection may not be initiated from a page loaded over HTTPS.
./node_modules/react-dev-utils/webpackHotDevClient.js
node_modules/react-dev-utils/webpackHotDevClient.js:60
__webpack_require__
/home/my_user/projects/my_project/frontend/webpack/bootstrap:785
Of course, the problem is that webpack uses websockets for hot reload notifications, and the default code assumes that the webpack server is available at ws://localost. In reality, the page was loaded with https. So the hot reloading code tries to create an insecure websocket to ws://localhost, from a page that was loaded with https.
Since the oauth2 client MUST use https, the obvious solution would be to turn off hot reloading completely. But that would slow down the development. To work efficiently, I need hot reloading. This would only work if I could also forward the websocket of the hot reloading client from nginx to my local webpack server. In other words: make it work through wss:// instead of ws://.
However, I do not know how to do this. Is it even possible to re-route the hot reload client? Is there an option for that? I can see that it is possible to turn off hot reloading. But I do not see any way to re-route the URL for the websocket.
UPDATE - this is not needed anymore, solved in v3.3.1 https://github.com/facebook/create-react-app/pull/8079 . But there are still packages that depend on an older version. In those cases, the solution provided below may be used.
Since create-react-app 3.4.0 released only couple weeks after your post, you can now precise these environment variables:
WDS_SOCKET_HOST
WDS_SOCKET_PORT
WDS_SOCKET_PATH
Check this commit for more details: create-react-app#822422c
I have found a solution. It is really a hack, but it can be used for testing oauth2 clients with https, your own websockets and webpack dev server's own socks-node websocket at the same time.
Install all required packages
Edit your node_modules/react-dev-utils/webpackHotDevClient.js file
Replace this:
// Connect to WebpackDevServer via a socket.
var connection = new WebSocket(
url.format({
protocol: 'ws',
hostname: window.location.hostname,
port: window.location.port,
// Hardcoded in WebpackDevServer
pathname: '/sockjs-node',
})
);
With this:
// Connect to WebpackDevServer via a socket.
var connection = new WebSocket(
url.format({
protocol: 'wss',
hostname: window.location.hostname,
port: window.location.port,
// Hardcoded in WebpackDevServer
pathname: '/sockjs-node',
})
);
This will force nodejs-socket to use wss instead of ws. If the nodejs-socket is also tunneled through your web server to your local webpack dev server, then it works!
It would be great if this code could use ws / wss depending on the protocol of window.location.

How to redirect api requests to express port on WAMP

I have a React app making requests to an express api server which is running on port 9000.
In dev I use a proxy setting in my package.json which works as expected:
"proxy": "http://localhost:9000/"
I have now built and deployed both the api and the client and have deployed them both to the www folder on WAMP. The api is working fine as I can interact with it using Postman. The client is also up and running however it is now trying to call the api on the wrong port:
http://localhost/api/...
How can I redirect the api requests to port 9000 on WAMP?
http://localhost:9000/api/...
The proxy feature is not for the production. It is meant to be used for development only. Proxy in development is just a productivity feature. It’s useful if you serve the single-page app from your API server in production, but want to use the development server provided by create-react-app while you work on the app. However proxy is just that: a development feature. It is not meant for production.
You can read more about it here. If you really want to point a port, add it to app.js of your node application and consider starting server on that port.
In the end I decided to remove the proxy setting and prefix the requests with the correct api domain. This way it works as expected on both dev and prod:
private domain = "http://localhost:9000";
get(url: string, params?: any): Promise<any> {
return new Promise(async (resolve, reject) => {
try {
const result = await trackPromise(
axios.get(this.domain + url, { params: params })
);
return resolve(result.data);
} catch (error) {
return reject(error.response.data.message);
}
});
}

/sockjs-node/info?t=1515290831331 after deploying MEAN app to Heroku

I'm using the starter provided by mean.io for a simple MEAN application. Under development I don't have issues with sockjs-node requests:
http://localhost:3000/sockjs-node/info?t=1515290831331
However, once I deploy on Heroku, the application fails to load data using the following requests:
http://sleepy-escarpment-60068.herokuapp.com:8817/sockjs-node/info?t=1515290831331
I decided to test that request using postman, but I had no success as well. However, I noticed a minor issue when trying to request data from that URL. It was that when deployed on Heroku, it adds the port assigned by Heroku which is 8817 in my case. I decided to test a similar URL, but this time without using heroku's port (8817):
http://sleepy-escarpment-60068.herokuapp.com/sockjs-node/info?t=1515290831331
In this scenario, I could receive a response data. Therefore, my idea is to change the path of the URL once the app sends the request from:
http://sleepy-escarpment-60068.herokuapp.com:8817/sockjs-node/info?t=1515290831331
to
http://sleepy-escarpment-60068.herokuapp.com/sockjs-node/info?t=1515290831331
However, I'm not sure neither how to do it, nor where to apply this solution on the application. I've been googling around to find a solution for the /sockjs-node/info?t=1515290831331 issue and people suggest to redirect the request using the webpack.dev.js file:
devServer: {
port: METADATA.port,
host: METADATA.host,
historyApiFallback: true,
watchOptions: {
// if you're using Docker you may need this
// aggregateTimeout: 300,
// poll: 1000,
ignored: /node_modules/
},
disableHostCheck: true,
proxy: {
'**/sockjs-node': {
changeOrigin: true,
pathRewrite: {
'**/sockjs-node': '/test'
}
},
}
I haven't had success trying to implement that solution. Am I doing something wrong on my code? Is that the right solution for the "/sockjs-node/info?t=1515290831331 failed to get response data" issue after deploying my app to Heroku?

Socket-io client keeps sending connect requests

I am creating app that includes some real-time features. I use Node.js, SocketIO and Express + React on frontend. My backend handles both http and ws requests. I use webpack-dev-server with proxy option to redirect client's requests to my local server.
Some days ago, although I haven't touch neither webpack configuration nor backend code, single call io({ path: '/socket' }) on client side results in sending A LOT of connect requests to my backend.
The reason is not HMR, component's rerendering or some loop on client side. I am sure client side calls io({ path: '/socket' }) only once. Even when I change branches to some old ones (in which the problem for sure didn't exist), after reinstalling all node_modules, the issue remains. So this can be some network/hardware related even. I use Windows 10, Node.js 6.
Exemplary logs in debug mode that my backend produces in the console:
This is only part of logs, in general it keeps connecting really fast and doesn't stop.
Any idea what is going on here?
The problem was that socket.io kept using long polling even if websocket was already available. To solve this I passed transports: ['websocket'] to connection options like this:
import io from 'socket.io-client';
io({ path: '/socket', transports: ['websocket'] });

Disabling Meteor 2 minute server timeout?

How can one remove/increase the server side connection timeout from Meteor when using server side routes with Iron Router?
There is a fix when using vanilla Node: https://contourline.wordpress.com/2011/03/30/preventing-server-timeout-in-node-js/
But I cannot figure out where to put the code in the above sample to make it work with Meteor and Iron Router
Here's a sample route:
Router.route('veryslowroute', {
path: '/veryslow',
where: 'server',
action: function () {
// Route never rendered in browser. Reducing value here to 110000 will render just fine
Meteor._sleepForMs(120000);
// These I've tried:
// this.response.setTimeout(0);
// this.response.connection.setTimeout(0);
// this.response.connection.server.setTimeout(0);
this.response.writeHead(200, {'Content-Type':'application/json'});
this.response.end(JSON.stringify({
key: 'Sorry for being so slow'
}));
}
});
So it appears the timeout needs to be set somewhere else. Anybody?
EDIT: It appears that this isn't about NodeJS but Meteor itself, likely the webapp-package. Still couldn't find a workaround. Same thing happens when using webapp directly without Iron Router.
EDIT: Now there is an issue in Meteor: https://github.com/meteor/meteor/issues/3826

Resources