Skip to content

Commit 3450af6

Browse files
author
Benoit Ngo
committed
Fixing request proxy to send stream instead of loading body. It fix binaries file upload that use the proxy aswell
1 parent f6115dc commit 3450af6

File tree

2 files changed

+85
-3
lines changed

2 files changed

+85
-3
lines changed

apps/front/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"generate": "nuxt generate",
77
"preview": "nuxt preview",
88
"postinstall": "nuxt prepare",
9-
"lint": "eslint nuxt.config.ts --fix ; nuxi typecheck ; eslint ./src/"
9+
"lint": "eslint nuxt.config.ts --fix ; nuxi typecheck && eslint ./src/"
1010
},
1111
"devDependencies": {
1212
"@nuxt/eslint-config": "^0.1.1",

apps/front/src/server/api/[...].ts

+84-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
import { defineEventHandler, H3Event, proxyRequest } from "h3";
2-
1+
import {
2+
defineEventHandler,
3+
H3Event,
4+
RequestHeaders,
5+
getMethod,
6+
getRequestHeaders,
7+
sendProxy as _sendProxy,
8+
} from "h3";
39
/**
410
* Beware
511
* Using the SSR, cookies are transmitted to the proxy BUT
@@ -25,6 +31,81 @@ import { defineEventHandler, H3Event, proxyRequest } from "h3";
2531

2632
import logger from "~/utils/logger";
2733

34+
/**
35+
* This code override proxyRequest from h3
36+
*/
37+
38+
/**
39+
* start - this code is not exported from h3
40+
*/
41+
export interface ProxyOptions {
42+
headers?: RequestHeaders | HeadersInit;
43+
fetchOptions?: RequestInit;
44+
fetch?: typeof fetch;
45+
sendStream?: boolean;
46+
cookieDomainRewrite?: string | Record<string, string>;
47+
cookiePathRewrite?: string | Record<string, string>;
48+
onResponse?: (event: H3Event, response: Response) => void;
49+
}
50+
51+
const ignoredHeaders = new Set([
52+
'transfer-encoding',
53+
'connection',
54+
'keep-alive',
55+
'upgrade',
56+
'expect',
57+
'host',
58+
]);
59+
60+
export function getProxyRequestHeaders(event: H3Event) {
61+
const headers = Object.create(null);
62+
const reqHeaders = getRequestHeaders(event);
63+
// eslint-disable-next-line no-restricted-syntax
64+
for (const name in reqHeaders) {
65+
if (!ignoredHeaders.has(name)) {
66+
headers[name] = reqHeaders[name];
67+
}
68+
}
69+
return headers;
70+
}
71+
72+
/**
73+
* end - this code is not exported from h3
74+
*/
75+
76+
/**
77+
* This code override h3 default behavior:
78+
* Instead of reading the body we send the body as the stream, allowing better memory usage + prevent utf8 decoding
79+
* */
80+
async function proxyRequest(
81+
event: H3Event,
82+
target: string,
83+
opts: ProxyOptions = {},
84+
) {
85+
const method = getMethod(event);
86+
87+
// Headers
88+
const headers = getProxyRequestHeaders(event);
89+
if (opts.fetchOptions?.headers) {
90+
Object.assign(headers, opts.fetchOptions.headers);
91+
}
92+
if (opts.headers) {
93+
Object.assign(headers, opts.headers);
94+
}
95+
return _sendProxy(event, target, {
96+
...opts,
97+
fetchOptions: {
98+
headers,
99+
method,
100+
body: method !== "GET" && method !== "HEAD" ? event.node.req : undefined,
101+
...opts.fetchOptions,
102+
} as RequestInit,
103+
});
104+
}
105+
106+
/**
107+
* Here we use the proxy as a default request
108+
*/
28109
export default defineEventHandler(async (event: H3Event) => {
29110
const { API_URL } = useRuntimeConfig();
30111
const target = new URL(event.req.url as string, API_URL);
@@ -33,6 +114,7 @@ export default defineEventHandler(async (event: H3Event) => {
33114
headers: {
34115
host: target.host,
35116
},
117+
sendStream: true,
36118
fetchOptions: {
37119
redirect: "manual",
38120
},

0 commit comments

Comments
 (0)