-
-
Notifications
You must be signed in to change notification settings - Fork 5.8k
/
proxy.ts
106 lines (95 loc) · 2.88 KB
/
proxy.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import * as http from 'http'
import { createDebugger } from '../../utils'
import httpProxy from 'http-proxy'
import { HMR_HEADER } from '../ws'
import { ViteDevServer } from '..'
import { Connect } from 'types/connect'
import { HttpProxy } from 'types/http-proxy'
import chalk from 'chalk'
const debug = createDebugger('vite:proxy')
export interface ProxyOptions extends HttpProxy.ServerOptions {
/**
* rewrite path
*/
rewrite?: (path: string) => string
/**
* configure the proxy server (e.g. listen to events)
*/
configure?: (proxy: HttpProxy.Server, options: ProxyOptions) => void
/**
* webpack-dev-server style bypass function
*/
bypass?: (
req: http.IncomingMessage,
res: http.ServerResponse,
options: ProxyOptions
) => void | null | undefined | false | string
}
export function proxyMiddleware({
httpServer,
config
}: ViteDevServer): Connect.NextHandleFunction {
const options = config.server.proxy!
// lazy require only when proxy is used
const proxies: Record<string, [HttpProxy.Server, ProxyOptions]> = {}
Object.keys(options).forEach((context) => {
let opts = options[context]
if (typeof opts === 'string') {
opts = { target: opts } as ProxyOptions
}
const proxy = httpProxy.createProxyServer(opts) as HttpProxy.Server
proxy.on('error', (err) => {
config.logger.error(`${chalk.red(`http proxy error:`)}\n${err.stack}`, {
timestamp: true
})
})
if (opts.configure) {
opts.configure(proxy, opts)
}
// clone before saving because http-proxy mutates the options
proxies[context] = [proxy, { ...opts }]
})
httpServer.on('upgrade', (req, socket, head) => {
const url = req.url!
for (const context in proxies) {
if (url.startsWith(context)) {
const [proxy, opts] = proxies[context]
if (
(opts.ws || opts.target?.toString().startsWith('ws:')) &&
req.headers['sec-websocket-protocol'] !== HMR_HEADER
) {
if (opts.rewrite) {
req.url = opts.rewrite(url)
}
proxy.ws(req, socket, head)
}
}
}
})
return (req, res, next) => {
const url = req.url!
for (const context in proxies) {
if (url.startsWith(context)) {
const [proxy, opts] = proxies[context]
if (opts.bypass) {
const bypassResult = opts.bypass(req, res, opts)
if (typeof bypassResult === 'string') {
req.url = bypassResult
debug(`bypass: ${req.url} -> ${bypassResult}`)
return next()
} else if (bypassResult === false) {
debug(`bypass: ${req.url} -> 404`)
return res.end(404)
}
}
debug(`${req.url} -> ${opts.target || opts.forward}`)
if (opts.rewrite) {
req.url = opts.rewrite(req.url!)
}
proxy.web(req, res)
return
}
}
next()
}
}