Skip to content

When you enable websocket in proxyMiddleware Why Invalid frame header came in some microservices #1076

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
2 tasks done
abhishek73magar opened this issue Mar 10, 2025 · 0 comments

Comments

@abhishek73magar
Copy link

Checks

Describe the bug (be clear and concise)

I don't know why but we we use route as path like /forestfire/socket.io it will throw invalid header in some of my socket.io microservice but not other why i am not sure?
server.ts

import express, { Application, NextFunction, Request, Response } from 'express'
import { createProxyMiddleware } from 'http-proxy-middleware'
import cors from 'cors'
import cookieParser from 'cookie-parser'
import setHeaders from 'libs/set-headers'
import { PORT } from 'config/config'
import {  ClientRequest, IncomingMessage, Server } from 'http'
import routes from 'config/routes'
import accessConfig, { verifyToken } from 'libs/access-config'
import EventEmitter from 'events'

// default is 12 is not enough for this project cause we use a lot of proxy
EventEmitter.defaultMaxListeners = 20 

const proxyReq = (openAccess: boolean | Array<string> | undefined) => (proxyReq: ClientRequest, req: Request, res: Response) => {
  // accessConfig(openAccess)(req, res) // check if user has access to the route
  if(openAccess === true) return;
  if(Array.isArray(openAccess)){
    if(openAccess.includes(req.path)) return;
  }

  // check auth token;
  const token = req.cookies.alert_token
  if(token){
    const data = verifyToken(token)
    if(data) proxyReq.setHeader('data', JSON.stringify({ user: data}))
  }
 
}

const proxyRes = (proxyRes: IncomingMessage, req: Request, res: Response) => {
  // for(let oldKey in proxyRes.headers){
  //   if(oldKey === 'data') continue;
  //   let newkey = oldKey.replace(/((?:^|-)[a-z])/g, function(val) { return val.toUpperCase() });
  //   newkey = newkey.replace(/(-Os-)/g, function (val) { return val.toUpperCase() });
  //   proxyRes.headers[newkey] = proxyRes.headers[oldKey];
  //   delete proxyRes.headers[oldKey];
  // }
}

const start = (): Promise<Server> => {
  return new Promise((resolve, reject) => {
    const app: Application = express();
    app.use(cors({
      origin: ['http://localhost:3000', 'http://localhost:3001', 'http://192.168.4.161:3000'],
      credentials: true,
    }))

    app.use(cookieParser())
    app.use(setHeaders)

    routes.forEach(({ route, target, pathRewrite, openAccess }) => {
      let rewrite_path: Record<string, string> | undefined = undefined
      // HPM (HTTP PROXY MIDDLEWARE)
      if(!target) return console.log(`[HPM] Proxy target not found for route: ${route} -> ${target}`)
      // add logs for each proxy
      console.log(`[HPM] Proxy created: ${route} -> ${target}`)
      if(pathRewrite) {
        const [key, value] = pathRewrite
        rewrite_path = { [key]: value }
        // console.log(`[HPM] Proxy rewrite rule created: "${key}" ~> "${value}"`)
      }
      
      // if(route === '/'){
      //   // use this / routes for the main frontend app if we not use like this it will thorow Invalid frame header
      //   app.use(route, createProxyMiddleware({ target, changeOrigin: true, logger: console, ws: false, on: { proxyReq: proxyReq(openAccess), proxyRes } }))
      //   return;
      // }

      const proxyMiddleware = createProxyMiddleware({
        target: target,
        pathFilter: route,
        changeOrigin: true,
        pathRewrite: rewrite_path,
        // timeout: 1000 * 60, // 1 minute
        // proxyTimeout: 1000 * 60 * 2, //  default 2 minute
        ws: route === '/' ? true : true, // for websocket proxy 
        logger: console, 
        on: { 
          proxyReq: proxyReq(openAccess), 
          proxyRes 
        }
      })

      app.use(proxyMiddleware)
    })

    const server = app.listen(PORT, () => resolve(server))
  })
}

export { start }

routes.ts

import services from 'config/services'

const authNotAllow = [
  '/auth/login', '/auth/create', '/auth/verify-recaptcha', '/auth/user-access',
  '/auth/forgot-password', '/auth/change-password', "/auth/update-user", "/auth/refresh-page",
  "/auth/socket.io"
]
const helperAuthNotAllow = [
  '/helper/location',
  '/helper/test', '/helper/wsm-date', '/helper/basin', '/helper/district', '/helper/province', '/helper/municipality', '/helper/nepal-boundary', '/helper/seiscomp-station', '/helper/earthquake-event',
  '/helper/wms-forecast', '/helper/wms-forecast2', '/helper/wms-satellite',
  '/helper/river_layer', '/helper/boundaries/province', '/helper/boundaries/district', '/helper/boundaries/municipality', '/helper/geoglows/get-comid', '/helper/geoglows/comid-list'
]

const _createTuple = (key: string, value: string): [string, string] => [key, value]
interface Routes {
  service: string,
  route: string,
  target?: string
  pathRewrite?: [string, string],
  openAccess?: boolean | string[],
  // ws?: boolean
}


const routes: Routes[] = [
  // { service: 'meroalert', route: '/mero-alert', target: services.meroalert, pathRewrite: _createTuple('/mero_alert', ''), openAccess: true },
  // { service: 'meteoblue', route: '/meteoblue', target: services.meteoblue, openAccess: true },
  // { service: 'wrf-forecast', route: '/wrf-forecast', target: services.wrfForecast, pathRewrite: _createTuple('/wrf-forecast', ''), openAccess: true },
  // { service: 'geoserver', route: '/geoserver', target: services.geoserver, openAccess: true },
  // { service: 'seiscomp-history', route: '/seiscomp-history', target: services.seiscomp_history, openAccess: true},
  // { service: "seiscomp-xml", route: "/seiscomp-xml", target: services.seiscomp_xml, openAccess: true, pathRewrite: _createTuple('/seiscomp-xml', '') },
  // { service: 'seiscomp', route: '/seiscomp/socket.io', target: services.seiscomp, openAccess: true },
  // { service: 'lightning-threats', route: '/lightning-threats/socket.io', target: services.lightning_threats, openAccess: true },
  // { service: 'lightning', route: '/lightning/socket.io', target: services.lightning, openAccess: true },
  { service: 'helper', route: '/helper', target: services.helper, pathRewrite: _createTuple('/helper', ''), openAccess: helperAuthNotAllow},
  { service: 'personal-alert', route: '/personal-alert', target: services.personal_alert, openAccess: false },
  // { service: 'forestfire', route: '/forestfire/socket.io', target: services.forestfire, openAccess: true },
  // { service: 'cap', route: '/cap/socket.io', target: services.cap, openAccess: true },
  // { service: 'auth', route: '/auth/socket.io', target: services.auth, openAccess: true },
  { service: 'auth', route: '/auth/google', target: services.auth, openAccess: true },
  { service: 'auth', route: '/auth', target: services.auth, openAccess: authNotAllow },
  { service: 'personal-dashboard', route: '/personal-dashboard', target: services.personal_dashbarod, pathRewrite: _createTuple('/personal_dashboard', ''), openAccess: true },
  { service: 'aws_dashboard', route: '/aws_dashboard', target: services.aws_dashboard, pathRewrite: _createTuple("/aws_dashboard", ''), openAccess: true },
  { service: 'hs_dashboard', route: '/hs_dashboard', target: services.hs_dashboard, pathRewrite: _createTuple("/hs_dashboard", ''), openAccess: true },
  { service: 'watershed_dashboard', route: '/watershed_dashboard', target: services.watershed_dashboard, pathRewrite: _createTuple("/watershed_dashboard", ''), openAccess: true },
  { service: 'alertnepal', route: '/', target: services.alertnepal, openAccess: true },
]


export default routes;

this is my code

when i disable websocket in / path it, the invalid headers error resolved but i like to tell you this why its happening i don't know please review once

or tell me the if i am doing somthing wrong

its happen to /auth/socket.io only i don't know why but in /auth microservice credentials is true.
but when i directly connect that invalid header error is not coming

Step-by-step reproduction instructions

1. use the following code which is provided in decription.
2. ...

Expected behavior (be clear and concise)

http proxy is worked fine & other socket.io microservice is working also good but, which /auth/socket.io it will throw warning when you enable ws in / routes

How is http-proxy-middleware used in your project?

i have personal project which have more then 12 microservices so i used for centralized the services.

What http-proxy-middleware configuration are you using?

latest http-proxy-middleware (V3)

 const proxyMiddleware = createProxyMiddleware({
        target: target,
        pathFilter: route,
        changeOrigin: true,
        pathRewrite: rewrite_path,
        // timeout: 1000 * 60, // 1 minute
        // proxyTimeout: 1000 * 60 * 2, //  default 2 minute
        ws: route === '/' ? true : true, // for websocket proxy 
        logger: console, 
        on: { 
          proxyReq: proxyReq(openAccess), 
          proxyRes 
        }
      })

What OS/version and node/version are you seeing the problem?

Ubuntu 24.04.2 LTS x86_64 & node 23

Additional context (optional)

No response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants