Skip to content
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

feat(v2): replace http-proxy-middleware to httpxy #240

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,32 +54,26 @@
]
},
"dependencies": {
"@nuxt/kit": "^3.13.1",
"connect": "^3.7.0",
"@nuxt/kit": "^3.13.2",
"consola": "^3.0.0",
"fs-extra": "^11.1.0",
"h3": "^1.6.0",
"http-proxy-middleware": "^2.0.6",
"httpxy": "^0.1.5",
"lodash-es": "^4.17.21",
"meow": "^13.2.0",
"ofetch": "^1.1.1",
"openapi-types": "^12.1.3",
"type-fest": "^4.1.0",
"ufo": "^1.1.2",
"ufo": "^1.5.4",
"unconfig": "^0.6.0"
},
"resolutions": {
"http-proxy": "npm:[email protected]"
},
"devDependencies": {
"@commitlint/cli": "19.5.0",
"@commitlint/config-conventional": "19.5.0",
"@nuxt/module-builder": "0.8.4",
"@nuxt/schema": "3.13.2",
"@privyid/eslint-config-persona": "0.27.0",
"@privyid/nuapi": "0.2.1",
"@types/connect": "3.4.38",
"@types/express": "5.0.0",
"@types/fs-extra": "11.0.4",
"@types/lodash-es": "4.17.12",
"@typescript-eslint/eslint-plugin": "5.62.0",
Expand Down
2 changes: 1 addition & 1 deletion playground/server.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default defineServer([
name : 'force-download',
baseUrl : '/force/download',
proxyType : 'dynamic',
allowFrom : ['dummyjson.com'],
allowFrom : ['dummyjson.com', 'httpbin.org'],
downloadExt : '.pdf',
downloadHeader: true,
},
Expand Down
42 changes: 39 additions & 3 deletions src/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import type * as http from 'node:http'
import { type H3Event, createEvent } from 'h3'
import { type Options } from 'http-proxy-middleware'
import type { Request, Response } from 'http-proxy-middleware/dist/types'
import { type ProxyServerOptions as Options } from 'httpxy'
import type {
OnEndCallback,
OnErrorCallback,
OnStartCallback,
OnProxyReqCallback,
OnProxyReqWsCallback,
OnProxyResCallback,
PathRewrite,
} from './types'

export interface SwaggerConfig {
/**
Expand Down Expand Up @@ -70,6 +78,34 @@ export interface ApiServer extends Options {
* Swagger transformer config
*/
swagger?: SwaggerConfig,
/**
* path Rewrite
*/
pathRewrite?: PathRewrite,
/**
* on proxy error
*/
onError?: OnErrorCallback,
/**
* on proxy request
*/
onProxyReq?: OnProxyReqCallback,
/**
* on proxy response
*/
onProxyRes?: OnProxyResCallback,
/**
* on proxy request (websocket)
*/
onProxyReqWs?: OnProxyReqWsCallback,
/**
* on proxy start
*/
onStart?: OnStartCallback,
/**
* on proxy end
*/
onEnd?: OnEndCallback,
}

export type EventInterceptor = (proxyEvent: H3Event, event: H3Event, options?: Options) => unknown | Promise<unknown>
Expand All @@ -79,7 +115,7 @@ export type EventInterceptor = (proxyEvent: H3Event, event: H3Event, options?: O
* @param handler H3-Compabilities event handler
*/
export function defineEventInterceptor (handler: EventInterceptor) {
return (proxy: http.ClientRequest | http.IncomingMessage, req: Request, res: Response, options?: Options) => {
return (proxy: http.ClientRequest | http.IncomingMessage, req: http.IncomingMessage, res: http.ServerResponse, options?: Options) => {
const event = createEvent(req, res)
const proxyEvent = createEvent(
proxy as unknown as http.IncomingMessage,
Expand Down
55 changes: 55 additions & 0 deletions src/core/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import type * as http from 'node:http'
import type * as net from 'node:net'
import type * as url from 'node:url'
import type { ProxyServerOptions } from 'httpxy'

type Target = NonNullable<ProxyServerOptions['target'] | ProxyServerOptions['forward']>

/**
* Use types based on the events listeners from http-proxy
* https://github.com/DefinitelyTyped/DefinitelyTyped/blob/51504fd999031b7f025220fab279f1b2155cbaff/types/http-proxy/index.d.ts
*/
export type OnErrorCallback = (
err: Error,
req: http.IncomingMessage,
res: http.ServerResponse,
target?: string | Partial<url.Url>
) => void

export type OnProxyResCallback = (
proxyRes: http.IncomingMessage,
req: http.IncomingMessage,
res: http.ServerResponse,
) => void

export type OnProxyReqCallback = (
proxyReq: http.ClientRequest,
req: http.IncomingMessage,
res: http.ServerResponse,
options: ProxyServerOptions
) => void

export type OnProxyReqWsCallback = (
proxyReq: http.ClientRequest,
req: http.IncomingMessage,
socket: net.Socket,
options: ProxyServerOptions,
head: any
) => void

export type OnEndCallback = (
req: http.IncomingMessage,
res: http.ServerResponse,
proxyRes: http.IncomingMessage,
) => void

export type OnStartCallback = (
req: http.IncomingMessage,
res: http.ServerResponse,
target: Target,
) => void

export type PathRewrite =
| Record<string, string>
| ((path: string, req: http.IncomingMessage) => string | undefined)
| ((path: string, req: http.IncomingMessage) => Promise<string>)
3 changes: 2 additions & 1 deletion src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ export default defineNuxtModule<ModuleOptions>({

addServerHandler({
middleware: true,
handler : resolve('./runtime/proxy'),
lazy : true,
handler : resolve('./runtime/server/middleware/proxy'),
})

if (options.autoImport !== false) {
Expand Down
16 changes: 0 additions & 16 deletions src/runtime/proxy.ts

This file was deleted.

26 changes: 0 additions & 26 deletions src/runtime/proxy/basic.ts

This file was deleted.

95 changes: 0 additions & 95 deletions src/runtime/proxy/dynamic.ts

This file was deleted.

28 changes: 28 additions & 0 deletions src/runtime/server/middleware/proxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {
useBase,
createRouter,
defineLazyEventHandler,
} from 'h3'
import { joinURL } from 'ufo'
import configs from '~/server.config'
import { createProxyBasic } from '../utils/proxy-basic'
import { createProxyDynamic } from '../utils/proxy-dynamic'
import { consola as console } from 'consola'

export default defineLazyEventHandler(() => {
const router = createRouter()

for (const config of configs) {
if (config.proxyType === 'dynamic')
router.use(config.baseUrl, createProxyDynamic(config))
else if (config.targetUrl) {
router.use(
joinURL(config.baseUrl, '**'),
useBase(config.baseUrl, createProxyBasic(config)),
)
} else
console.warn('[NHP] Skip create proxy "%s", missing target url', config.name)
}

return router.handler
})
26 changes: 26 additions & 0 deletions src/runtime/server/utils/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { ProxyServer } from 'httpxy'
import type { ApiServer } from '../../../core'

// https://github.com/chimurai/http-proxy-middleware/blob/7341704d0aa9d1606dfd37ebfdffddd34c894784/src/_handlers.ts#L20-L27
export const PROXY_EVENT_MAP = {
onProxyReq : 'proxyReq',
onProxyRes : 'proxyRes',
onProxyReqWs: 'proxyReqWs',
onStart : 'start',
onEnd : 'end',
onError : 'error',
} as const

export type EventName = keyof typeof PROXY_EVENT_MAP

export type HooksOptions = Pick<ApiServer, EventName>

export function installHook (proxy: ProxyServer, config: HooksOptions): void {
for (const key in PROXY_EVENT_MAP) {
const name = PROXY_EVENT_MAP[key as EventName]
const handler = config[key as EventName]

if (typeof handler === 'function')
proxy.on(name, handler)
}
}
Loading