@edgeone/opennextjs-pages 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/content/server.js +10 -0
- package/dist/build/functions/server.js +3 -8
- package/dist/build/routes.js +6 -16
- package/dist/build/templates/handler-monorepo.tmpl.js +6 -242
- package/dist/build/templates/handler.tmpl.js +2 -247
- package/dist/index.js +2 -2
- package/dist/run/handlers/tags-handler.cjs +1 -1
- package/package.json +1 -1
|
@@ -191,6 +191,16 @@ var copyNextDependencies = async (ctx) => {
|
|
|
191
191
|
);
|
|
192
192
|
}
|
|
193
193
|
await Promise.all(promises);
|
|
194
|
+
const packageJsonPath = join(ctx.serverHandlerDir, "package.json");
|
|
195
|
+
if (existsSync(packageJsonPath)) {
|
|
196
|
+
try {
|
|
197
|
+
const packageJsonContent = JSON.parse(await readFile(packageJsonPath, "utf-8"));
|
|
198
|
+
packageJsonContent.type = "module";
|
|
199
|
+
await writeFile(packageJsonPath, JSON.stringify(packageJsonContent, null, 2));
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.warn("Warning: Failed to update package.json with ES module type:", error);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
194
204
|
const serverHandlerRequire = createRequire(posixJoin(ctx.serverHandlerDir, ":internal:"));
|
|
195
205
|
if (ctx.nextVersion) {
|
|
196
206
|
await patchNextModules(ctx, ctx.nextVersion, serverHandlerRequire.resolve);
|
|
@@ -98,25 +98,20 @@ var getHandlerFile = async (ctx) => {
|
|
|
98
98
|
const templateVariables = {
|
|
99
99
|
"{{useRegionalBlobs}}": ctx.useRegionalBlobs.toString()
|
|
100
100
|
};
|
|
101
|
-
let runtime_shim = "";
|
|
102
|
-
const getRuntimeShim = ctx.getRuntimeShim;
|
|
103
|
-
if (getRuntimeShim) {
|
|
104
|
-
runtime_shim = getRuntimeShim();
|
|
105
|
-
}
|
|
106
101
|
if (ctx.relativeAppDir.length !== 0) {
|
|
107
102
|
const template2 = await readFile(join(templatesDir, "handler-monorepo.tmpl.js"), "utf-8");
|
|
108
103
|
console.log("ctx.lambdaWorkingDirectory", ctx.lambdaWorkingDirectory);
|
|
109
104
|
console.log("ctx.nextServerHandler", ctx.nextServerHandler);
|
|
110
105
|
templateVariables["{{cwd}}"] = posixJoin(ctx.lambdaWorkingDirectory);
|
|
111
106
|
templateVariables["{{nextServerHandler}}"] = posixJoin(ctx.nextServerHandler);
|
|
112
|
-
return applyTemplateVariables(
|
|
107
|
+
return applyTemplateVariables(template2, templateVariables);
|
|
113
108
|
}
|
|
114
109
|
const template = await readFile(join(templatesDir, "handler.tmpl.js"), "utf-8");
|
|
115
|
-
return applyTemplateVariables(
|
|
110
|
+
return applyTemplateVariables(template, templateVariables);
|
|
116
111
|
};
|
|
117
112
|
var writeHandlerFile = async (ctx) => {
|
|
118
113
|
const handler = await getHandlerFile(ctx);
|
|
119
|
-
await writeFile(join(ctx.serverHandlerRootDir, `
|
|
114
|
+
await writeFile(join(ctx.serverHandlerRootDir, `handler.js`), handler);
|
|
120
115
|
};
|
|
121
116
|
var clearStaleServerHandlers = async (ctx) => {
|
|
122
117
|
await rm(ctx.serverFunctionsDir, { recursive: true, force: true });
|
package/dist/build/routes.js
CHANGED
|
@@ -97,27 +97,17 @@ var createRouteMeta = async (ctx) => {
|
|
|
97
97
|
path: path2,
|
|
98
98
|
...config
|
|
99
99
|
}));
|
|
100
|
-
const
|
|
101
|
-
if (!fs.existsSync(
|
|
102
|
-
fs.mkdirSync(
|
|
100
|
+
const serverHandlerDir = ctx.serverHandlerDir;
|
|
101
|
+
if (!fs.existsSync(serverHandlerDir)) {
|
|
102
|
+
fs.mkdirSync(serverHandlerDir, { recursive: true });
|
|
103
103
|
}
|
|
104
|
-
const metaFilePath = path.join(
|
|
105
|
-
|
|
106
|
-
if (fs.existsSync(metaFilePath)) {
|
|
107
|
-
try {
|
|
108
|
-
const existingContent = fs.readFileSync(metaFilePath, "utf-8");
|
|
109
|
-
existingMetaData = JSON.parse(existingContent);
|
|
110
|
-
} catch (error) {
|
|
111
|
-
console.warn("Failed to parse existing meta.json:", error);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
const mergedMetaData = {
|
|
115
|
-
...existingMetaData,
|
|
104
|
+
const metaFilePath = path.join(serverHandlerDir, "meta.json");
|
|
105
|
+
const metaData = {
|
|
116
106
|
nextRoutes: routesArray
|
|
117
107
|
};
|
|
118
108
|
fs.writeFileSync(
|
|
119
109
|
metaFilePath,
|
|
120
|
-
JSON.stringify(
|
|
110
|
+
JSON.stringify(metaData, null, 2),
|
|
121
111
|
"utf-8"
|
|
122
112
|
);
|
|
123
113
|
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { createServer } from 'http';
|
|
2
1
|
import {
|
|
3
2
|
createRequestContext,
|
|
4
3
|
runWithRequestContext,
|
|
@@ -6,151 +5,19 @@ import {
|
|
|
6
5
|
import { getTracer } from './{{cwd}}/.edgeone/dist/run/handlers/tracer.cjs'
|
|
7
6
|
import * as serverHandler from './{{cwd}}/.edgeone/dist/run/handlers/server.js'
|
|
8
7
|
|
|
9
|
-
|
|
10
8
|
process.chdir('./{{cwd}}')
|
|
11
9
|
|
|
12
10
|
// Set feature flag for regional blobs
|
|
13
11
|
process.env.USE_REGIONAL_BLOBS = '{{useRegionalBlobs}}'
|
|
14
12
|
|
|
15
|
-
|
|
16
|
-
async function handleResponse(res, response, passHeaders = {}) {
|
|
17
|
-
const startTime = Date.now();
|
|
18
|
-
|
|
19
|
-
// 没有响应 - 404 拦截
|
|
20
|
-
if (!response) {
|
|
21
|
-
const requestId = passHeaders['functions-request-id'] || '';
|
|
22
|
-
res.writeHead(404, {
|
|
23
|
-
'Functions-Request-Id': requestId,
|
|
24
|
-
'eo-pages-inner-scf-status': '404',
|
|
25
|
-
'eo-pages-inner-status-intercept': 'true'
|
|
26
|
-
});
|
|
27
|
-
res.end(JSON.stringify({
|
|
28
|
-
error: "Not Found",
|
|
29
|
-
message: "The requested path does not exist"
|
|
30
|
-
}));
|
|
31
|
-
const endTime = Date.now();
|
|
32
|
-
console.log(`Pages response status: 404`);
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
try {
|
|
37
|
-
if (response instanceof Response) {
|
|
38
|
-
const requestId = passHeaders['functions-request-id'] || '';
|
|
39
|
-
const responseStatus = response.status;
|
|
40
|
-
|
|
41
|
-
const headers = Object.fromEntries(response.headers);
|
|
42
|
-
Object.assign(headers, passHeaders);
|
|
43
|
-
|
|
44
|
-
// 添加状态码区分的 headers
|
|
45
|
-
headers['Functions-Request-Id'] = requestId;
|
|
46
|
-
|
|
47
|
-
// 如果 Response 中已经设置了,使用它的值;否则使用 responseStatus
|
|
48
|
-
if (!headers['eo-pages-inner-scf-status']) {
|
|
49
|
-
headers['eo-pages-inner-scf-status'] = String(responseStatus);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// 如果 Response 中已经设置了,使用它的值;否则默认为 false
|
|
53
|
-
if (!headers['eo-pages-inner-status-intercept']) {
|
|
54
|
-
headers['eo-pages-inner-status-intercept'] = 'false';
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (response.headers.get('eop-client-geo')) {
|
|
58
|
-
// 删除 eop-client-geo 头部
|
|
59
|
-
response.headers.delete('eop-client-geo');
|
|
60
|
-
}
|
|
61
|
-
// 处理 set-cookie 头部
|
|
62
|
-
if (response.headers.has('set-cookie')) {
|
|
63
|
-
const cookieArr = response.headers.getSetCookie();
|
|
64
|
-
|
|
65
|
-
headers['set-cookie'] = cookieArr;
|
|
66
|
-
}
|
|
67
|
-
// 检查是否是流式响应
|
|
68
|
-
const isStream = response.body && (
|
|
69
|
-
response.headers.get('content-type')?.includes('text/event-stream') ||
|
|
70
|
-
response.headers.get('transfer-encoding')?.includes('chunked') ||
|
|
71
|
-
response.body instanceof ReadableStream ||
|
|
72
|
-
typeof response.body.pipe === 'function' ||
|
|
73
|
-
response.headers.get('x-content-type-stream') === 'true'
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
if (isStream) {
|
|
77
|
-
// 设置流式响应所需的头部
|
|
78
|
-
const streamHeaders = {
|
|
79
|
-
...headers
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
if (response.headers.get('content-type')?.includes('text/event-stream')) {
|
|
83
|
-
streamHeaders['Content-Type'] = 'text/event-stream';
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
res.writeHead(response.status, streamHeaders);
|
|
87
|
-
|
|
88
|
-
if (typeof response.body.pipe === 'function') {
|
|
89
|
-
response.body.pipe(res);
|
|
90
|
-
} else {
|
|
91
|
-
const reader = response.body.getReader();
|
|
92
|
-
try {
|
|
93
|
-
while (true) {
|
|
94
|
-
const { done, value } = await reader.read();
|
|
95
|
-
if (done) break;
|
|
96
|
-
|
|
97
|
-
if (value instanceof Uint8Array || Buffer.isBuffer(value)) {
|
|
98
|
-
res.write(value);
|
|
99
|
-
} else {
|
|
100
|
-
const chunk = new TextDecoder().decode(value);
|
|
101
|
-
res.write(chunk);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
} finally {
|
|
105
|
-
reader.releaseLock();
|
|
106
|
-
res.end();
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
} else {
|
|
110
|
-
// 普通响应
|
|
111
|
-
res.writeHead(response.status, headers);
|
|
112
|
-
const body = await response.text();
|
|
113
|
-
res.end(body);
|
|
114
|
-
}
|
|
115
|
-
} else {
|
|
116
|
-
// 非 Response 对象,直接返回 JSON
|
|
117
|
-
const requestId = passHeaders['functions-request-id'] || '';
|
|
118
|
-
res.writeHead(200, {
|
|
119
|
-
'Content-Type': 'application/json',
|
|
120
|
-
'Functions-Request-Id': requestId,
|
|
121
|
-
'eo-pages-inner-scf-status': '200',
|
|
122
|
-
'eo-pages-inner-status-intercept': 'false'
|
|
123
|
-
});
|
|
124
|
-
res.end(JSON.stringify(response));
|
|
125
|
-
}
|
|
126
|
-
} catch (error) {
|
|
127
|
-
// 用户函数内部错误 内部502 - 拦截
|
|
128
|
-
const requestId = passHeaders['functions-request-id'] || '';
|
|
129
|
-
res.writeHead(502, {
|
|
130
|
-
'Functions-Request-Id': requestId,
|
|
131
|
-
'eo-pages-inner-scf-status': '502',
|
|
132
|
-
'eo-pages-inner-status-intercept': 'true'
|
|
133
|
-
});
|
|
134
|
-
res.end(JSON.stringify({
|
|
135
|
-
error: "Internal Server Error",
|
|
136
|
-
message: error.message
|
|
137
|
-
}));
|
|
138
|
-
} finally {
|
|
139
|
-
const endTime = Date.now();
|
|
140
|
-
console.log(`Pages response status: ${response?.status || 'unknown'}`);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
13
|
let cachedHandler
|
|
146
|
-
export default async function
|
|
14
|
+
export default async function handler(req, context = {}) {
|
|
147
15
|
const requestContext = createRequestContext(req, context)
|
|
148
16
|
const tracer = getTracer()
|
|
149
17
|
|
|
150
18
|
const handlerResponse = await runWithRequestContext(requestContext, () => {
|
|
151
19
|
return tracer.withActiveSpan('Next.js Server Handler', async (span) => {
|
|
152
20
|
if (!cachedHandler) {
|
|
153
|
-
// const { default: handler } = await import('{{nextServerHandler}}')
|
|
154
21
|
cachedHandler = serverHandler.default
|
|
155
22
|
}
|
|
156
23
|
const response = await cachedHandler(req, context, span, requestContext)
|
|
@@ -158,117 +25,14 @@ export default async function eoHandler (req, context) {
|
|
|
158
25
|
})
|
|
159
26
|
})
|
|
160
27
|
|
|
28
|
+
if (requestContext.serverTiming) {
|
|
29
|
+
handlerResponse.headers.set('server-timing', requestContext.serverTiming);
|
|
30
|
+
}
|
|
31
|
+
|
|
161
32
|
return handlerResponse
|
|
162
33
|
}
|
|
163
34
|
|
|
164
|
-
|
|
165
35
|
export const config = {
|
|
166
36
|
path: '/*',
|
|
167
37
|
preferStatic: true,
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
const port = 9000;
|
|
171
|
-
|
|
172
|
-
// 实时流转换函数
|
|
173
|
-
function createReadableStreamFromRequest(req) {
|
|
174
|
-
return new ReadableStream({
|
|
175
|
-
start(controller) {
|
|
176
|
-
req.on('data', chunk => {
|
|
177
|
-
// 将Buffer转换为Uint8Array
|
|
178
|
-
const uint8Array = new Uint8Array(chunk);
|
|
179
|
-
controller.enqueue(uint8Array);
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
req.on('end', () => {
|
|
183
|
-
controller.close();
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
req.on('error', error => {
|
|
187
|
-
controller.error(error);
|
|
188
|
-
});
|
|
189
|
-
},
|
|
190
|
-
|
|
191
|
-
cancel() {
|
|
192
|
-
// 清理资源
|
|
193
|
-
req.destroy();
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const server = createServer(async (req, res) => {
|
|
199
|
-
try {
|
|
200
|
-
const requestStartTime = Date.now();
|
|
201
|
-
|
|
202
|
-
// 构造 handler 需要的 req 对象(可根据需要扩展)
|
|
203
|
-
// 用 eo-pages-host 替换 host
|
|
204
|
-
const originalHost = req.headers['eo-pages-host'] || req.headers['host'];
|
|
205
|
-
const handlerReq = {
|
|
206
|
-
...req,
|
|
207
|
-
headers: {
|
|
208
|
-
...req.headers,
|
|
209
|
-
'accept-encoding': 'identity',
|
|
210
|
-
'host': originalHost,
|
|
211
|
-
},
|
|
212
|
-
method: req.method,
|
|
213
|
-
url: req.url,
|
|
214
|
-
};
|
|
215
|
-
|
|
216
|
-
// 读取 body(如果有)
|
|
217
|
-
// let body = [];
|
|
218
|
-
// req.on('data', chunk => body.push(chunk));
|
|
219
|
-
// await new Promise(resolve => req.on('end', resolve));
|
|
220
|
-
// if (body.length > 0) {
|
|
221
|
-
// handlerReq.body = Buffer.concat(body);
|
|
222
|
-
// }
|
|
223
|
-
|
|
224
|
-
handlerReq.body = createReadableStreamFromRequest(req);
|
|
225
|
-
|
|
226
|
-
const response = await eoHandler(handlerReq, {});
|
|
227
|
-
|
|
228
|
-
// response.headers.set('functions-request-id', req.headers['x-scf-request-id'] || '');
|
|
229
|
-
|
|
230
|
-
const requestEndTime = Date.now();
|
|
231
|
-
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
232
|
-
let pathname = url.pathname;
|
|
233
|
-
|
|
234
|
-
if (pathname !== '/' && pathname.endsWith('/')) {
|
|
235
|
-
pathname = pathname.slice(0, -1);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
let fullPath = '';
|
|
239
|
-
if (req.headers.host === 'localhost:9000') {
|
|
240
|
-
fullPath = pathname;
|
|
241
|
-
} else {
|
|
242
|
-
const host = req.headers['eo-pages-host'];
|
|
243
|
-
const xForwardedProto = req.headers['x-forwarded-proto'];
|
|
244
|
-
|
|
245
|
-
fullPath = (xForwardedProto || 'https') + '://' + host + req.url;
|
|
246
|
-
|
|
247
|
-
if (fullPath.endsWith('?')) {
|
|
248
|
-
fullPath = fullPath.slice(0, -1);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
console.log(`Pages request path: ${fullPath}`);
|
|
253
|
-
|
|
254
|
-
await handleResponse(res, response, {
|
|
255
|
-
'functions-request-id': req.headers['x-scf-request-id'] || ''
|
|
256
|
-
});
|
|
257
|
-
return;
|
|
258
|
-
} catch (error) {
|
|
259
|
-
console.log(`Pages response status: 502`);
|
|
260
|
-
// 用户函数内部错误 内部502 - 拦截
|
|
261
|
-
const requestId = req.headers['x-scf-request-id'] || '';
|
|
262
|
-
res.statusCode = 502;
|
|
263
|
-
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
264
|
-
res.setHeader('Functions-Request-Id', requestId);
|
|
265
|
-
res.setHeader('eo-pages-inner-scf-status', '502');
|
|
266
|
-
res.setHeader('eo-pages-inner-status-intercept', 'true');
|
|
267
|
-
res.end('<html><body><h1>Error</h1><p>'+error.message+'</p></body></html>');
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
server.listen(port, () => {
|
|
272
|
-
console.log('Server is running on http://localhost:9000');
|
|
273
|
-
});
|
|
274
|
-
|
|
38
|
+
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
|
|
2
|
-
import { createServer } from 'http';
|
|
3
2
|
import {
|
|
4
3
|
createRequestContext,
|
|
5
4
|
runWithRequestContext,
|
|
@@ -7,141 +6,8 @@ import {
|
|
|
7
6
|
import serverHandler from './.edgeone/dist/run/handlers/server.js';
|
|
8
7
|
import { getTracer } from './.edgeone/dist/run/handlers/tracer.cjs';
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
async function handleResponse(res, response, passHeaders = {}) {
|
|
12
|
-
const startTime = Date.now();
|
|
13
|
-
|
|
14
|
-
// 没有响应 - 404 拦截
|
|
15
|
-
if (!response) {
|
|
16
|
-
const requestId = passHeaders['functions-request-id'] || '';
|
|
17
|
-
res.writeHead(404, {
|
|
18
|
-
'Functions-Request-Id': requestId,
|
|
19
|
-
'eo-pages-inner-scf-status': '404',
|
|
20
|
-
'eo-pages-inner-status-intercept': 'true'
|
|
21
|
-
});
|
|
22
|
-
res.end(JSON.stringify({
|
|
23
|
-
error: "Not Found",
|
|
24
|
-
message: "The requested path does not exist"
|
|
25
|
-
}));
|
|
26
|
-
const endTime = Date.now();
|
|
27
|
-
console.log(`Pages response status: 404`);
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
if (response instanceof Response) {
|
|
33
|
-
const requestId = passHeaders['functions-request-id'] || '';
|
|
34
|
-
const responseStatus = response.status;
|
|
35
|
-
|
|
36
|
-
const headers = Object.fromEntries(response.headers);
|
|
37
|
-
Object.assign(headers, passHeaders);
|
|
38
|
-
|
|
39
|
-
// 添加状态码区分的 headers
|
|
40
|
-
headers['Functions-Request-Id'] = requestId;
|
|
41
|
-
|
|
42
|
-
// 如果 Response 中已经设置了,使用它的值;否则使用 responseStatus
|
|
43
|
-
if (!headers['eo-pages-inner-scf-status']) {
|
|
44
|
-
headers['eo-pages-inner-scf-status'] = String(responseStatus);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// 如果 Response 中已经设置了,使用它的值;否则默认为 false
|
|
48
|
-
if (!headers['eo-pages-inner-status-intercept']) {
|
|
49
|
-
headers['eo-pages-inner-status-intercept'] = 'false';
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// 删除内部 header
|
|
53
|
-
if (response.headers.get('eop-client-geo')) {
|
|
54
|
-
response.headers.delete('eop-client-geo');
|
|
55
|
-
}
|
|
56
|
-
// 处理 set-cookie 头部
|
|
57
|
-
if (response.headers.has('set-cookie')) {
|
|
58
|
-
const cookieArr = response.headers.getSetCookie();
|
|
59
|
-
headers['set-cookie'] = cookieArr;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// 检查是否是流式响应
|
|
63
|
-
const isStream = response.body && (
|
|
64
|
-
response.headers.get('content-type')?.includes('text/event-stream') ||
|
|
65
|
-
response.headers.get('transfer-encoding')?.includes('chunked') ||
|
|
66
|
-
response.body instanceof ReadableStream ||
|
|
67
|
-
typeof response.body.pipe === 'function' ||
|
|
68
|
-
response.headers.get('x-content-type-stream') === 'true'
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
if (isStream) {
|
|
72
|
-
// 设置流式响应所需的头部
|
|
73
|
-
const streamHeaders = {
|
|
74
|
-
...headers
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
if (response.headers.get('content-type')?.includes('text/event-stream')) {
|
|
78
|
-
streamHeaders['Content-Type'] = 'text/event-stream';
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
res.writeHead(response.status, streamHeaders);
|
|
82
|
-
|
|
83
|
-
if (typeof response.body.pipe === 'function') {
|
|
84
|
-
response.body.pipe(res);
|
|
85
|
-
} else {
|
|
86
|
-
const reader = response.body.getReader();
|
|
87
|
-
try {
|
|
88
|
-
while (true) {
|
|
89
|
-
const { done, value } = await reader.read();
|
|
90
|
-
if (done) break;
|
|
91
|
-
|
|
92
|
-
if (value instanceof Uint8Array || Buffer.isBuffer(value)) {
|
|
93
|
-
res.write(value);
|
|
94
|
-
} else {
|
|
95
|
-
const chunk = new TextDecoder().decode(value);
|
|
96
|
-
res.write(chunk);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
} finally {
|
|
100
|
-
reader.releaseLock();
|
|
101
|
-
// scf可能会立即冻结环境上下文,导致后续日志无法输出,通过延时来确保日志输出
|
|
102
|
-
setTimeout(() => {
|
|
103
|
-
res.end();
|
|
104
|
-
}, 1);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
} else {
|
|
108
|
-
// 普通响应
|
|
109
|
-
res.writeHead(response.status, headers);
|
|
110
|
-
const body = await response.text();
|
|
111
|
-
res.end(body);
|
|
112
|
-
}
|
|
113
|
-
} else {
|
|
114
|
-
// 非 Response 对象,直接返回 JSON
|
|
115
|
-
const requestId = passHeaders['functions-request-id'] || '';
|
|
116
|
-
res.writeHead(200, {
|
|
117
|
-
'Content-Type': 'application/json',
|
|
118
|
-
'Functions-Request-Id': requestId,
|
|
119
|
-
'eo-pages-inner-scf-status': '200',
|
|
120
|
-
'eo-pages-inner-status-intercept': 'false'
|
|
121
|
-
});
|
|
122
|
-
res.end(JSON.stringify(response));
|
|
123
|
-
}
|
|
124
|
-
} catch (error) {
|
|
125
|
-
// 用户函数内部错误 内部502 - 拦截
|
|
126
|
-
const requestId = passHeaders['functions-request-id'] || '';
|
|
127
|
-
res.writeHead(502, {
|
|
128
|
-
'Functions-Request-Id': requestId,
|
|
129
|
-
'eo-pages-inner-scf-status': '502',
|
|
130
|
-
'eo-pages-inner-status-intercept': 'true'
|
|
131
|
-
});
|
|
132
|
-
res.end(JSON.stringify({
|
|
133
|
-
error: "Internal Server Error",
|
|
134
|
-
message: error.message
|
|
135
|
-
}));
|
|
136
|
-
} finally {
|
|
137
|
-
const endTime = Date.now();
|
|
138
|
-
console.log(`Pages response status: ${response?.status || 'unknown'}`);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
|
|
143
9
|
process.env.USE_REGIONAL_BLOBS = 'true';
|
|
144
|
-
export default async function handler(req, context) {
|
|
10
|
+
export default async function handler(req, context = {}) {
|
|
145
11
|
const requestContext = createRequestContext(req, context);
|
|
146
12
|
const tracer = getTracer();
|
|
147
13
|
|
|
@@ -162,115 +28,4 @@ export default async function handler(req, context) {
|
|
|
162
28
|
export const config = {
|
|
163
29
|
path: '/*',
|
|
164
30
|
preferStatic: true,
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
const port = 9000;
|
|
168
|
-
|
|
169
|
-
// 实时流转换函数
|
|
170
|
-
function createReadableStreamFromRequest(req) {
|
|
171
|
-
return new ReadableStream({
|
|
172
|
-
start(controller) {
|
|
173
|
-
req.on('data', chunk => {
|
|
174
|
-
// 将Buffer转换为Uint8Array
|
|
175
|
-
const uint8Array = new Uint8Array(chunk);
|
|
176
|
-
controller.enqueue(uint8Array);
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
req.on('end', () => {
|
|
180
|
-
controller.close();
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
req.on('error', error => {
|
|
184
|
-
controller.error(error);
|
|
185
|
-
});
|
|
186
|
-
},
|
|
187
|
-
|
|
188
|
-
cancel() {
|
|
189
|
-
// 清理资源
|
|
190
|
-
req.destroy();
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const server = createServer(async (req, res) => {
|
|
196
|
-
try {
|
|
197
|
-
const requestStartTime = Date.now();
|
|
198
|
-
|
|
199
|
-
// 构造 handler 需要的 req 对象(可根据需要扩展)
|
|
200
|
-
// 用 eo-pages-host 替换 host
|
|
201
|
-
const originalHost = req.headers['eo-pages-host'] || req.headers['host'];
|
|
202
|
-
const handlerReq = {
|
|
203
|
-
...req,
|
|
204
|
-
headers: {
|
|
205
|
-
...req.headers,
|
|
206
|
-
'accept-encoding': 'identity',
|
|
207
|
-
'host': originalHost,
|
|
208
|
-
},
|
|
209
|
-
method: req.method,
|
|
210
|
-
url: req.url,
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
// 读取 body(如果有)
|
|
216
|
-
// let body = [];
|
|
217
|
-
// req.on('data', chunk => body.push(chunk));
|
|
218
|
-
// await new Promise(resolve => req.on('end', resolve));
|
|
219
|
-
// if (body.length > 0) {
|
|
220
|
-
// handlerReq.body = Buffer.concat(body);
|
|
221
|
-
// }
|
|
222
|
-
|
|
223
|
-
handlerReq.body = createReadableStreamFromRequest(req);
|
|
224
|
-
|
|
225
|
-
const response = await handler(handlerReq, {});
|
|
226
|
-
|
|
227
|
-
// 不要在这里设置 functions-request-id,避免重复
|
|
228
|
-
// response.headers.set('functions-request-id', req.headers['x-scf-request-id'] || '');
|
|
229
|
-
// const requestEndTime = Date.now();
|
|
230
|
-
|
|
231
|
-
// 解析请求路径
|
|
232
|
-
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
233
|
-
let pathname = url.pathname;
|
|
234
|
-
|
|
235
|
-
if (pathname !== '/' && pathname.endsWith('/')) {
|
|
236
|
-
pathname = pathname.slice(0, -1);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
let fullPath = '';
|
|
240
|
-
if (req.headers.host === 'localhost:9000') {
|
|
241
|
-
fullPath = pathname;
|
|
242
|
-
} else {
|
|
243
|
-
const host = req.headers['eo-pages-host'];
|
|
244
|
-
const xForwardedProto = req.headers['x-forwarded-proto'];
|
|
245
|
-
|
|
246
|
-
fullPath = (xForwardedProto || 'https') + '://' + host + req.url;
|
|
247
|
-
|
|
248
|
-
if (fullPath.endsWith('?')) {
|
|
249
|
-
fullPath = fullPath.slice(0, -1);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
console.log(`Pages request path: ${fullPath}`);
|
|
254
|
-
|
|
255
|
-
// console.log(`Request processing time: ${requestEndTime - requestStartTime}ms`);
|
|
256
|
-
await handleResponse(res, response, {
|
|
257
|
-
'functions-request-id': req.headers['x-scf-request-id'] || ''
|
|
258
|
-
});
|
|
259
|
-
return;
|
|
260
|
-
} catch (error) {
|
|
261
|
-
console.log(`Pages response status: 502`);
|
|
262
|
-
// 用户函数内部错误 内部502 - 拦截
|
|
263
|
-
const requestId = req.headers['x-scf-request-id'] || '';
|
|
264
|
-
res.statusCode = 502;
|
|
265
|
-
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
266
|
-
res.setHeader('Functions-Request-Id', requestId);
|
|
267
|
-
res.setHeader('eo-pages-inner-scf-status', '502');
|
|
268
|
-
res.setHeader('eo-pages-inner-status-intercept', 'true');
|
|
269
|
-
res.end('<html><body><h1>Error</h1><p>'+error.message+'</p></body></html>');
|
|
270
|
-
}
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
server.listen(port, () => {
|
|
274
|
-
console.log('Server is running on http://localhost:9000');
|
|
275
|
-
});
|
|
276
|
-
|
|
31
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -35,9 +35,9 @@ var onBuild = async (options) => {
|
|
|
35
35
|
// copyStaticAssets(ctx),
|
|
36
36
|
copyStaticContent(ctx),
|
|
37
37
|
copyPrerenderedContent(ctx),
|
|
38
|
-
createServerHandler(ctx)
|
|
38
|
+
createServerHandler(ctx),
|
|
39
|
+
createRouteMeta(ctx)
|
|
39
40
|
]);
|
|
40
|
-
createRouteMeta(ctx);
|
|
41
41
|
};
|
|
42
42
|
var onPostBuild = async (options) => {
|
|
43
43
|
console.log("onPostBuild");
|
|
@@ -28,7 +28,7 @@ module.exports = __toCommonJS(tags_handler_exports);
|
|
|
28
28
|
|
|
29
29
|
// package.json
|
|
30
30
|
var name = "@edgeone/opennextjs-pages";
|
|
31
|
-
var version = "0.0.
|
|
31
|
+
var version = "0.0.7";
|
|
32
32
|
|
|
33
33
|
// src/run/handlers/tags-handler.cts
|
|
34
34
|
var import_request_context = require("./request-context.cjs");
|