I have a create-react-app dev server proxying backend connections (as one does). Suddenly websocket proxying stopped working.
My setupProxy.js looks like this:
const proxy = require('http-proxy-middleware');
module.exports = function(app) {
const port = process.env.BACKEND_PORT || '8080';
const target = `http://localhost:${port}`;
app.use(proxy(['/path/to/socket'], {
target,
ws: true,
onProxyReqWs: function(proxyReq, req, socket) {
socket.on('error', err => console.log(err));
console.log('socket is destroyed', socket.destroyed)
},
logLevel: 'debug',
}));
app.use(proxy(shouldProxy, {
target,
logLevel: 'debug',
}));
(where shouldProxy is a function, since my logic for when to proxy is... non-trivial).
When the browser (Firefox 71 or Chrome 79) creates a websocket connection, I can see that the backend gets the request and responds normally, but the browser gets a 400 Bad request and the dev-server console has this:
[HPM] GET /path/to/socket -> http://localhost:8080
socket is destroyed true
[HPM] Upgrading to WebSocket
Error [ERR_STREAM_DESTROYED]: Cannot call write after a stream was destroyed
at Socket.Writable.write (_stream_writable.js:321:17)
at ClientRequest.<anonymous> ([...]/node_modules/http-proxy/lib/http-proxy/passes/ws-incoming.js:143:14)
at ClientRequest.emit (events.js:305:20)
at Socket.socketOnData (_http_client.js:508:11)
at Socket.emit (events.js:305:20)
at addChunk (_stream_readable.js:341:12)
at readableAddChunk (_stream_readable.js:316:11)
at Socket.Readable.push (_stream_readable.js:250:10)
at TCP.onStreamRead (internal/stream_base_commons.js:186:23) {
code: 'ERR_STREAM_DESTROYED'
}
[HPM] Client disconnected
So something seems to be destroying the socket very early in the proxying process, but I cannot fathom what.
I currently run with node 13.5.0, http-proxy 1.18.0 and http-proxy-middleware 0.20.0; I've tried downgrading node to 12.14.0 and HPM to 0.19.1, to no avail.
This was an issue with create-react-app 3.3.0, caused by this bug in webpack-dev-server. Adding "webpack-dev-server": "3.10.1" to the resolutions section of package.json and SKIP_PREFLIGHT_CHECK=true to .env fixed it.
Related
I created a graphql subscription server which runs on port 7777 with the path /subscriptions/graphql for both HTTP, WebSocket protocol which is absolutely working fine when I directly used the URL with other services.
HTTP : http://localhost:7777/subscriptions/graphql
websocket: ws://localhost:7777/subscriptions/graphql
Subscription server is a microservices just like the other services we have. Now my aim is to do a reverse proxy in the gateway. I wanted to do a reverse proxy for both HTTP, WebSocket based connections.
For this, I wrote two middleware one for HTTP and one for Websocket. Http based middleware is working fine. Whereas the WebSocket is not working as expected.
Websocket based Middileware
import { NestMiddleware, Logger, Injectable } from '#nestjs/common';
import { createProxyMiddleware } from 'http-proxy-middleware';
#Injectable()
export class SubscriptionServiceWebSocketReverseProxyMiddleware
implements NestMiddleware {
/*
jscpd:ignore-start
*/
constructor(private readonly logger: Logger) { }
private proxy = createProxyMiddleware({
target: 'ws://localhost:7777/subscriptions/graphql',
secure: false,
changeOrigin: true,
ws: true,
onProxyReq: (proxyReq, req, res) => {
this.logger.debug(
`[SubscriptionServiceWebSocketReverseProxyMiddleware]: Proxying ${req.method} request originally made to '${req.originalUrl}'...`,
);
},
});
use(req: any, res: any, next: () => void) {
this.proxy(req, res, next);
}
/*
jscpd:ignore-end
*/
}
When the websocket request made from UI, I am getting below error
[Nest] 43743 - 08/24/2020, 3:20:20 PM [SubscriptionServiceWebSocketReverseProxyMiddleware]: Proxying GET request originally made to '/subscriptions/ws/graphql'...
[HPM] Upgrading to WebSocket
events.js:200
throw er; // Unhandled 'error' event
^
Error: read ECONNRESET
at TCP.onStreamRead (internal/stream_base_commons.js:200:27)
Emitted 'error' event on Socket instance at:
at emitErrorNT (internal/streams/destroy.js:92:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
at processTicksAndRejections (internal/process/task_queues.js:81:21) {
errno: 'ECONNRESET',
code: 'ECONNRESET',
syscall: 'read'
}
Note: I was able to see the log message inside the middleware which means there is no issue with middleware. I also see the subscription service alone is working as well.
I'm attempting to set up my first Node.js application on Windows Server. The application runs fine with the command:
node index.js
It'll run my application on localhost:8000. However, I want it to run on a subdomain on port 80, so I tried the following command:
set PORT=80 && set HOST=api.mydomain.com && node index.js
And here is my index.js file, which handles setting the PORT and HOST in the app.listen command:
import express from 'express';
import bodyParser from 'body-parser';
const expressJwt = require('express-jwt');
const config = require('./environment.json')[process.env.NODE_ENV || 'development'];
const app = express();
const port = +process.env.PORT || 8000;
const host = process.env.HOST || 'localhost';
// Skipping app.use commands...
app.get('/', root);
app.listen(port, host, 34, err => {
if (err) return console.error(err);
return console.log(`Server is listening on ${port}`);
});
Unfortunately, using a subdomain errors:
events.js:187
throw er; // Unhandled 'error' event
^
Error: getaddrinfo ENOTFOUND api.mydomain.com
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:60:26) Emitted 'error' event on Server instance at:
at GetAddrInfoReqWrap.doListen [as callback] (net.js:1485:12)
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:60:17) { errno: 'ENOTFOUND', code: 'ENOTFOUND', syscall: 'getaddrinfo',
hostname: 'api.mydomain.com ' }
What is the proper way to configure the Node.js application to run under the subdomain? If I were using IIS it'd be as simple as adding additional Bindings, but now I'm in Node.js land instead so have no idea how to go about it.
host
No for your application to run locally with this domain name you must modify the host configurations to make api.mydomaine.com correspond to the ip address 127.0.0.1 on your machine
I ended up just running it under IIS, using a reverse proxy. Then I could use IIS to set up the subdomain binding, much simpler...
https://dev.to/petereysermans/hosting-a-node-js-application-on-windows-with-iis-as-reverse-proxy-397b
Problem
On my node.js backend, I initialized a redis server:
const options = {
host: process.env.REDIS_HOST, // localhost
port: process.env.REDIS_PORT, // 6379 Redis standard port
db: 0,
// reconnect after
retryStrategy: times => Math.min(times * 50, 2000),
tls: {}
};
export const redis = new Redis(options);
Unfortunately, I always get this error message:
[ioredis] Unhandled error event: Error: connect ETIMEDOUT
at TLSSocket.<anonymous> (/home/pascal/vipfy/vipfy-backend/node_modules/ioredis/built/redis.js:298:31)
at Object.onceWrapper (events.js:273:13)
at TLSSocket.emit (events.js:182:13)
at TLSSocket.EventEmitter.emit (domain.js:442:20)
at TLSSocket.Socket._onTimeout (net.js:449:8)
at ontimeout (timers.js:436:11)
at tryOnTimeout (timers.js:300:5)
at listOnTimeout (timers.js:263:5)
at Timer.processTimers (timers.js:223:10)
I installed redis locally and use the redis-cli to ping the local server, no password is set. It always gives a positive answer, but I can't seem to be able to reach it via ioredis. Anybody an idea?
Make sure your redis server is running. You just try without options params, so it will try to connect your localhost redis automatically by host as localhost and port as 6379.
redis = new Redis();
If you don't have any specific advantage try following, I am using following one and works well.
Package : "redis": "^2.8.0"
Code :
var redis = require('redis');
var redis_conn = redis.createClient();
redis_conn.set("key", "val");
I have built an api and i want to test some of the endpoints.
I have a number of tests that are similar to the ones below. They are all all failing because of Error: ECONNREFUSED: Connection refused
tests
import { assert, expect } from "chai";
import request from "supertest";
import app from "./../src/index";
describe("Authentication", () => {
it("should respond with 200 product_id is authorised", async () => {
const result = await request(app).post("/api/auth")
.send({
product_id: "123",
origin: "localhost:3000",
})
.expect("Content-Type", /json/)
.expect(200);
});
it("should respond with session token", async () => {
const result = await request(app).post("/api/auth")
.send({
product_id: "123",
origin: "localhost:3000",
});
expect(result.body.data).to.have.property("token");
});
});
package.json
"test": "mocha -r ts-node/register --project tsconfig.json test/*.test.ts --exit"
errors:
> mocha -r ts-node/register --project tsconfig.json test/*.test.ts --exit
Server Running On: runner-sefsf-project-41-concurrent-0gdrs7:3000
Authentication
MongoDB Successfully Connected On: mongodb://localhost:27017/p
1) should respond with 200 product_id is authorised
2) should respond with p session token
Server
3) should be up
4) should throw 404 for unrecognized routes
Transaction
5) should respond with a new transction
0 passing (40ms)
5 failing
1) Authentication
should respond with 200 product_id is authorised:
Error: ECONNREFUSED: Connection refused
at Test.assert (node_modules/supertest/lib/test.js:165:15)
at assert (node_modules/supertest/lib/test.js:131:12)
at /eng/p-server/node_modules/supertest/lib/test.js:128:5
at Test.Request.callback (node_modules/superagent/lib/node/index.js:718:3)
at ClientRequest.req.once.err (node_modules/superagent/lib/node/index.js:646:10)
at Socket.socketErrorListener (_http_client.js:382:9)
at emitErrorNT (internal/streams/destroy.js:82:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:50:3)
at process._tickCallback (internal/process/next_tick.js:63:19)
2) Authentication
should respond with p session token:
Error: ECONNREFUSED: Connection refused
at Test.assert (node_modules/supertest/lib/test.js:165:15)
at assert (node_modules/supertest/lib/test.js:131:12)
at /eng/p-server/node_modules/supertest/lib/test.js:128:5
at Test.Request.callback (node_modules/superagent/lib/node/index.js:718:3)
at ClientRequest.req.once.err (node_modules/superagent/lib/node/index.js:646:10)
at Socket.socketErrorListener (_http_client.js:382:9)
at emitErrorNT (internal/streams/destroy.js:82:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:50:3)
at process._tickCallback (internal/process/next_tick.js:63:19)
Apparently the connection is being refused? But i'm not sure what it means by this specifically because you can see the server in the error log is connected and so is the mongo service.
index.ts
import Server from "./server";
export default new Server().server;
server.ts
import App from "./app";
class Server {
public server: any;
private instance: any;
private app: any;
private config: any;
constructor() {
this.instance = new App();
this.app = this.instance.app;
this.config = this.instance.config;
this.server = this.app.listen(this.config.port, this.config.hostname);
console.log("Server Running On: " + this.config.hostname + ":" + this.config.port);
}
}
export default Server;
Make sure your server is stopped before you run the test case using supertest as supertest run the api in that same port. So, you need to make that port free for use by supertest.
Since you are using this in your test file,
import request from "supertest";
import app from "./../src/index";
The app contains the domain URL like http://localhost:3135 and when you call the api like, request(app).post where request refers to the supertest module, you always need to make sure that the app is free. Which means, request('http://localhost:3135').post works when there is no process running on port 3135.
You can check the node running processes using pidof node (in linux)and kill every process to make sure the port is available or kill process for that specific port.
I encountered the same error and spend a couple of hours trying to figure out what was up. I was using the pg library and so it happens it needs to pick db options from the environment variables. My problem was I was calling dotenv.config() at the wrong place.
Background
I have a Node.js server using socket.io that accepts connections from clients via HTTPS.
I know this server works as I am able to connect to it via browser.
Problem
The problem is that I can't create a node app to connect to this server as a client.
I am using the following code:
const io = require("socket.io-client");
const socket = io.connect("https://my.website.com:3002", { secure: true, reconnect: true });
socket.on("connect", function(){
console.log("connected");
});
socket.on("disconnect", function(){
console.log("disconnected");
});
socket.on("error", console.error);
The server registers no connections, and this app logs no errors. It would seem that I am connecting to the wrong server, but this same URL works just fine when I use a browser.
Research
I have searched github and the official docs for an answer. Even similar questions from stackoverflow seem to not work:
Node.js client for a socket.io server
https://www.npmjs.com/package/socket.io-client
https://github.com/socketio/socket.io-client/issues/828
Question
What am I doing wrong ?
Answer
After realising, that not all errors feed into the "error" event ( special thanks to #RolandStarke ) I found that I was having a consistent XHR pool request:
{ Error: xhr poll error
at XHR.Transport.onError (/Users/pedro/Workspace/backend-stresser/node_modules/engine.io-client/lib/transport.js:64:13)
at Request.<anonymous> (/Users/pedro/Workspace/backend-stresser/node_modules/engine.io-client/lib/transports/polling-xhr.js:128:10)
at Request.Emitter.emit (/Users/pedro/Workspace/backend-stresser/node_modules/component-emitter/index.js:133:20)
at Request.onError (/Users/pedro/Workspace/backend-stresser/node_modules/engine.io-client/lib/transports/polling-xhr.js:310:8)
at Timeout._onTimeout (/Users/pedro/Workspace/backend-stresser/node_modules/engine.io-client/lib/transports/polling-xhr.js:257:18)
at ontimeout (timers.js:469:11)
at tryOnTimeout (timers.js:304:5)
at Timer.listOnTimeout (timers.js:264:5) type: 'TransportError', description: 503 }
Once I had this information, I made a quick search and found a solution to this issue, which seems to be a bug:
https://github.com/socketio/socket.io-client/issues/1097
The code I am now using is:
const socket = io.connect("https://my.website.com:3002", { secure: true, reconnection: true, rejectUnauthorized: false });
And it works as expected.
I have used this code in my client side and it worked:
import io from "socket.io-client"
const SERVER = "http://localhost:5000"
const socket = io(SERVER, { transports: ["websocket"] })