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.
Related
I Use NestJs as a backend server and angular as a frontend
it's okay with me when I use chrome on pc and I can do all my requests
but when I use my android chrome with DevTools I receive this error
message: "Http failure response for http://localhost:3000/users/login: 0 Unknown Error"
here is a snapshot of the error message
enter image description here
it also send the same error with pc chrome if i didnt open CORS on NestJs
here Is My COSR Config
import { ValidationPipe } from '#nestjs/common';
import { NestFactory } from '#nestjs/core';
import { NextFunction, Request, Response } from 'express';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use((req: Request, res: Response, next: NextFunction) => {
console.log(req);
next();
});
app.useGlobalPipes(new ValidationPipe());
app.enableCors({
origin: true,
methods: ['GET', 'PUT', 'POST', 'DELETE'],
exposedHeaders: ['x-auth'],
});
await app.listen(3000);
}
bootstrap();
by the way when I log the request on my nest app
I didn't receive any request
I think NestJsrefused it immediately
I found Where is the problem
I was using the localhost as a Backend IP and the application was connecting on my local pc Backend and that was the problem
I solved this by editing the Backend IP to the production IP
and finally, everything works good ,, Thanks All
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.
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"] })
I need to send my client HTTPS requests through an intranet proxy to a server.
I use both https and request+global-tunnel and neither solutions seem to work.
The similar code with 'http' works. Is there other settings I missed?
The code failed with an error:
REQUEST:
problem with request: tunneling socket could not be established, cause=socket hang up
HTTPS:
events.js:72
throw er; // Unhandled 'error' event
^
Error: socket hang up
at SecurePair.error (tls.js:1011:23)
at EncryptedStream.CryptoStream._done (tls.js:703:22)
at CleartextStream.read [as _read] (tls.js:499:24)
The code is the simple https test.
var http = require("https");
var options = {
host: "proxy.myplace.com",
port: 912,
path: "https://www.google.com",
headers: {
Host: "www.google.com"
}
};
http.get(options, function(res) {
console.log(res);
res.pipe(process.stdout);
});
You probably want to establish a TLS encrypted connection between your node app and target destination through a proxy.
In order to do this you need to send a CONNECT request with the target destination host name and port. The proxy will create a TCP connection to the target host and then simply forwards packs between you and the target destination.
I highly recommend using the request client. This package simplifies the process and handling of making HTTP/S requests.
Example code using request client:
var request = require('request');
request({
url: 'https://www.google.com',
proxy: 'http://97.77.104.22:3128'
}, function (error, response, body) {
if (error) {
console.log(error);
} else {
console.log(response);
}
});
Example code using no external dependencies:
var http = require('http'),
tls = require('tls');
var req = http.request({
host: '97.77.104.22',
port: 3128,
method: 'CONNECT',
path: 'twitter.com:443'
});
req.on('connect', function (res, socket, head) {
var tlsConnection = tls.connect({
host: 'twitter.com',
socket: socket
}, function () {
tlsConnection.write('GET / HTTP/1.1\r\nHost: twitter.com\r\n\r\n');
});
tlsConnection.on('data', function (data) {
console.log(data.toString());
});
});
req.end();