kartikk221 / hyper-express

High performance Node.js webserver with a simple-to-use API powered by uWebsockets.js under the hood.
MIT License
1.77k stars 97 forks source link

Could not proxy request to hyper-express server #180

Closed josejooj closed 1 year ago

josejooj commented 1 year ago

How my problem started

Hello again! I had posted about this a time ago

The post was basically about me not being able to proxy a react site to the api in hyper-express

I ended up opting for a "stop-gap solution", instead of making a proxy for the api, I just used axios and set the baseUrl as the API url, so I could make requests to the API without proxy, but the problem of not accepting requests via proxy was still there, and I thought I would have no problem with that anymore

Now, some context of my actual problem

Now I bought a VM on Google Cloud and set up a whole environment complete with nginx, below is the nginx configuration

server {
    listen 443 ssl;
    server_name dev.mywebsite.com;

    ssl_certificate /etc/letsencrypt/live/dev.mywebsite.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/dev.mywebsite.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:5173;
    }
}

server {
    listen 443 ssl;
    server_name api.dev.mywebsite.com;

    ssl_certificate /etc/letsencrypt/live/api.dev.mywebsite.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.dev.mywebsite.com/privkey.pem;

    location / {
       proxy_pass http://127.0.0.1:63031;
    }
}

So, what is the problem?

So the api is running, but not receiving proxy requests... This is my API code:

import HyperExpress, { UserRouteHandler } from 'hyper-express';
import { SQLClient } from './util/Database';
import { Routes } from './Routes';
import { inspect } from 'util';
import crypto from 'crypto';
import cors from 'cors';

const server = new HyperExpress.Server({
    fast_buffers: true,
    ssl_prefer_low_memory_usage: true,
    trust_proxy: true
});

const methods: Array<"get" | "use" | "post" | "delete" | "patch"> = ["get", "use", "post", "delete", "patch"];
const port = 63031;

server.use(cors()); // @ts-ignore
server.options('/*', cors());

for (const route of Routes.api.filter(x => x.use)) route.pattern !== "*" ? server.use(route.pattern, route.use!) : server.use(route.use!)
for (const route of Routes.api.filter(x => !x.use)) {
    for (const method of methods) {
        if (route[method]) server[method](route.pattern, route[method] as UserRouteHandler)
    }
}

for (const route of Routes.websocket) {
    server.upgrade(route.pattern, route.upgrade)
    server.ws(route.pattern, route.handler)
}

server.set_error_handler(async (req, res, error) => {

    let genRandomId = () => crypto.randomUUID().split("-").join("");
    let id = genRandomId();

    while ((await SQLClient.query(`SELECT FROM errors WHERE id = $1`, [id])).rowCount) id = genRandomId()

    const toinsert = {
        id,
        request: inspect(req, { depth: Infinity, maxArrayLength: Infinity }),
        response: inspect(res, { depth: Infinity, maxArrayLength: Infinity }),
        error: inspect(error),
        body: inspect(await req.json()), // @ts-ignore
        handler: `${req.route.handler}`
    }

    await SQLClient.query(
        `INSERT INTO errors (${Object.keys(toinsert)}) VALUES (${Object.keys(toinsert).map((x, i) => `$${i + 1}`)})`,
        Object.values(toinsert)
    )

    res._send(500, `Aconteceu um erro interno no servidor. Contate o suporte com o ID de erro: ${id}`);

})

server.listen(port).then((x) => {

    const routes: Record<string, string> = {};
    const table: Record<string, string>[] = [];

    for (const [method, routeObject] of Object.entries(server.routes)) {
        for (const route of Object.values(routeObject)) {
            if (!routes[route.pattern]) routes[route.pattern] = method.toUpperCase();
            else routes[route.pattern] += `, ${method.toUpperCase()}`;
        }
    }

    for (const [route, methods] of Object.entries(routes)) {
        const tableRow: Record<string, string> = {};
        const methodArray = methods.split(', ');
        tableRow['Route'] = route;
        for (const method of methodArray) tableRow[method] = '✅';
        table.push(tableRow);
    }

    console.table(table);
    console.log(`[API] - Estou online na porta ${port}`)

}).catch(e => console.log(`[API] - Ocorreu o seguinte erro ao abrir na porta ${port}`, e));

So, i want to know... What can i do to solve this? I like so much to work with hyper-express, i don't want to change to another module only for this...

kartikk221 commented 1 year ago

Hello, so the below error seems to be uWebsockets.js aka. hyper-express closing the connection forcefully before the request has properly been received.

*66 upstream prematurely closed connection while reading response header from upstream, client: 170.238.13.25, server: api.dev.mywebsite.com, request: "GET /status HTTP/1.1", upstream: "http://127.0.0.1:6 3031/status", host: "api.dev.mywebsite.com"

This can only occur in the following scenarios:

I would take the below steps to try and debug this problem further:

Also, can you provide to me the HTTP method, headers and body of the request you are sending to the API which gets prematurely closed by the server?

masfahru commented 1 year ago

Hopefully this help : https://github.com/uNetworking/uWebSockets.js/discussions/835#discussioncomment-5369383

kartikk221 commented 1 year ago

Ohh I see. That makes perfect sense. I also use http 1.1 in my own NGINX configurations for upstream with hyper-express hence never encountered this problem. That should solve it.