( httpServer: HttpServer | null, options: NonNullable<CommonServerOptions['proxy']>, config: ResolvedConfig, )
| 73 | } |
| 74 | |
| 75 | export function proxyMiddleware( |
| 76 | httpServer: HttpServer | null, |
| 77 | options: NonNullable<CommonServerOptions['proxy']>, |
| 78 | config: ResolvedConfig, |
| 79 | ): Connect.NextHandleFunction { |
| 80 | // lazy require only when proxy is used |
| 81 | const proxies: Record<string, [httpProxy.ProxyServer, ProxyOptions]> = {} |
| 82 | |
| 83 | Object.keys(options).forEach((context) => { |
| 84 | let opts = options[context] |
| 85 | if (!opts) { |
| 86 | return |
| 87 | } |
| 88 | if (typeof opts === 'string') { |
| 89 | opts = { target: opts, changeOrigin: true } |
| 90 | } |
| 91 | const proxy = httpProxy.createProxyServer(opts) |
| 92 | |
| 93 | if (opts.configure) { |
| 94 | opts.configure(proxy, opts) |
| 95 | } |
| 96 | |
| 97 | proxy.on('error', (err, _req, res) => { |
| 98 | // When it is ws proxy, res is net.Socket |
| 99 | if ('req' in res) { |
| 100 | config.logger.error( |
| 101 | `${colors.red(`http proxy error: ${res.req.url}`)}\n${err.stack}`, |
| 102 | { |
| 103 | timestamp: true, |
| 104 | error: err, |
| 105 | }, |
| 106 | ) |
| 107 | if (!res.headersSent && !res.writableEnded) { |
| 108 | res |
| 109 | .writeHead(502, { |
| 110 | 'Content-Type': 'text/plain', |
| 111 | }) |
| 112 | .end() |
| 113 | } |
| 114 | } else { |
| 115 | config.logger.error(`${colors.red(`ws proxy error:`)}\n${err.stack}`, { |
| 116 | timestamp: true, |
| 117 | error: err, |
| 118 | }) |
| 119 | res.end() |
| 120 | } |
| 121 | }) |
| 122 | |
| 123 | proxy.on('proxyReqWs', (proxyReq, _req, socket, options) => { |
| 124 | rewriteOriginHeader(proxyReq, options, config) |
| 125 | |
| 126 | socket.on('error', (err) => { |
| 127 | config.logger.error( |
| 128 | `${colors.red(`ws proxy socket error:`)}\n${err.stack}`, |
| 129 | { |
| 130 | timestamp: true, |
| 131 | error: err, |
| 132 | }, |
no test coverage detected