如何在没有 http 服务器的情况下在内部使用 koa app 回调?
How to use koa app callback internally without an http server?
我有一个基于 koa 的 js 应用程序并致力于 server-side 渲染。在应用程序的其余部分,我从 运行 连接 SSR 的同一台服务器加载一些脚本。虽然加载可以通过标准的 HTTP 请求,但速度会不必要地慢。所以我想简单地调用 koa 提供的 app.callback()
来将请求解析为请求文件的字符串。对于 SSR,我使用的是 jsdom,它加载文件并作为浏览器处理它们。
问题是我无法得到结果,resp。 body 的“服务器响应”。我试图模拟服务器请求和服务器响应,然后只读取套接字。我不确定这是否是最好的方法,但它似乎可行。但是,当我 运行 应用程序时,我只得到两个块 - 用于大型 froont-end 文件的字符串缓冲区。第一个块是 headers。其次是部分代码,但只有 64kB。我无法获得下一块。模拟的可写流似乎停止了。也许它被塞住了,但我不确定为什么以及是否完全没有。
如果我尝试加载小于 64kB 的脚本,请求会被正确解析并且流会结束。
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const { Writable } = require("stream");
const http = require("http");
const fetch = async (url, options) => {
const response = [];
let finishedReolve;
const finished = new Promise(resolve => (finishedReolve = resolve));
const socket = new Writable({
write: (data, encoding, cb) => {
console.log("write", data);
// outputs 2 times - 1. headers, 2. 64kB part of requested code
response.push(data);
cb();
return true;
},
destroy(err, cb) {
// Never gets called
console.log("destroy", err);
cb();
finishedReolve();
},
final(cb) {
// Never gets called
console.log("final");
cb();
finishedReolve();
},
});
const req = new http.IncomingMessage(socket);
req.method = "GET";
const parsedURL = new URL(url);
req.url = parsedURL.pathname;
const res = new http.ServerResponse(req);
res.assignSocket(req.socket);
res.on("prefinish", () => {
// Never gets called
finishedReolve();
});
await this.callback()(req, res);
await finished;
return response[0];
};
class CustomResourceLoader extends jsdom.ResourceLoader {
fetch(url, options) {
return fetch(url, options);
}
}
const dom = await JSDOM.fromFile(index_html_path, {
url: domain + ctx.req.url,
runScripts: "dangerously",
resources: new CustomResourceLoader(),
});
流有什么问题?有没有其他方法如何使用 app.callback()
来获取 koa 应用程序的输出?
问题是,可读流正在发送 64kB 的块,但我的可写流 highWaterMark
设置为默认的 16kB。这(可能)导致可读流在写入更多可写可以处理的数据后等待耗尽,这是在第一个 64kB 块之后。
解决方案是将 highWaterMark
设置为比可读流更多的值,例如
highWaterMark: 1024 * 64 * 2,
所以套接字看起来像这样:
const socket = new Writable({
highWaterMark: 1024 * 64 * 2,
write: (data, encoding, cb) => {
response.push(data);
cb();
return true;
},
destroy(err, cb) {
console.log("destroy", err);
cb();
finishedReolve();
},
final(cb) {
console.log("final");
cb();
finishedReolve();
},
});
另外,为了完成,我需要听听那个奇怪的事件 prefinish
。
我有一个基于 koa 的 js 应用程序并致力于 server-side 渲染。在应用程序的其余部分,我从 运行 连接 SSR 的同一台服务器加载一些脚本。虽然加载可以通过标准的 HTTP 请求,但速度会不必要地慢。所以我想简单地调用 koa 提供的 app.callback()
来将请求解析为请求文件的字符串。对于 SSR,我使用的是 jsdom,它加载文件并作为浏览器处理它们。
问题是我无法得到结果,resp。 body 的“服务器响应”。我试图模拟服务器请求和服务器响应,然后只读取套接字。我不确定这是否是最好的方法,但它似乎可行。但是,当我 运行 应用程序时,我只得到两个块 - 用于大型 froont-end 文件的字符串缓冲区。第一个块是 headers。其次是部分代码,但只有 64kB。我无法获得下一块。模拟的可写流似乎停止了。也许它被塞住了,但我不确定为什么以及是否完全没有。
如果我尝试加载小于 64kB 的脚本,请求会被正确解析并且流会结束。
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const { Writable } = require("stream");
const http = require("http");
const fetch = async (url, options) => {
const response = [];
let finishedReolve;
const finished = new Promise(resolve => (finishedReolve = resolve));
const socket = new Writable({
write: (data, encoding, cb) => {
console.log("write", data);
// outputs 2 times - 1. headers, 2. 64kB part of requested code
response.push(data);
cb();
return true;
},
destroy(err, cb) {
// Never gets called
console.log("destroy", err);
cb();
finishedReolve();
},
final(cb) {
// Never gets called
console.log("final");
cb();
finishedReolve();
},
});
const req = new http.IncomingMessage(socket);
req.method = "GET";
const parsedURL = new URL(url);
req.url = parsedURL.pathname;
const res = new http.ServerResponse(req);
res.assignSocket(req.socket);
res.on("prefinish", () => {
// Never gets called
finishedReolve();
});
await this.callback()(req, res);
await finished;
return response[0];
};
class CustomResourceLoader extends jsdom.ResourceLoader {
fetch(url, options) {
return fetch(url, options);
}
}
const dom = await JSDOM.fromFile(index_html_path, {
url: domain + ctx.req.url,
runScripts: "dangerously",
resources: new CustomResourceLoader(),
});
流有什么问题?有没有其他方法如何使用 app.callback()
来获取 koa 应用程序的输出?
问题是,可读流正在发送 64kB 的块,但我的可写流 highWaterMark
设置为默认的 16kB。这(可能)导致可读流在写入更多可写可以处理的数据后等待耗尽,这是在第一个 64kB 块之后。
解决方案是将 highWaterMark
设置为比可读流更多的值,例如
highWaterMark: 1024 * 64 * 2,
所以套接字看起来像这样:
const socket = new Writable({
highWaterMark: 1024 * 64 * 2,
write: (data, encoding, cb) => {
response.push(data);
cb();
return true;
},
destroy(err, cb) {
console.log("destroy", err);
cb();
finishedReolve();
},
final(cb) {
console.log("final");
cb();
finishedReolve();
},
});
另外,为了完成,我需要听听那个奇怪的事件 prefinish
。