我有一个简单的expressjs代理服务器,将请求中继到RESTful API,并将该API的响应中继回来。如果我使用 CURL 来访问它,就像这样:
curl -s "http://localhost:3000/api/findOne" \
-X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ /* request body */ }'
然后我将有效的 JSON 返回到 STDOUT。
但是如果我尝试从 JavaScript 前端
fetch
这样:
fetch("http://localhost:3000/api/findOne", {
method: "POST",
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(/* request body */),
})
.then((res) => res.json()) // .text() doesn't work either!
.then((res) => console.log(res))
.catch((e) => e);
然后我从 catch 块返回这个错误:
最糟糕的部分是,我让代理服务器打印出它接收到的请求以及它生成的从实际 RESTful API 中提取的请求,并且我在进行curl 调用时生成的输出和输出之间进行了比较它是在进行 fetch 调用时生成的,并且它们是“相同的”,逐个字符。这意味着代理服务器每次都做完全相同的事情,只是 fetch 出了问题,导致它无法解析结果,即使是纯文本,这很奇怪。 我在互联网上根本找不到任何关于此的信息,有人可以告诉我吗?谢谢。我对自己的网络开发技能有点生疏(已经脱离圈子好几年了)。
编辑:好的,我已经更进一步了:似乎发生的事情是我从代理服务器获得的输出被截断,就像,它只是停在输出流的中间,与 API 端点的原始输出进行比较。也许这使得无法解码?即便如此,它也应该可以被解码为文本,因为curl可以做到这一点,但JavaScript似乎无法做到这一点。此外,即使代理服务器的输出“不”至少明显被截断,也会发生解码错误。这是(稍微精简的)服务器代码:
import express, { Express, Request, Response } from 'express';
import dotenv from 'dotenv';
import bodyParser from 'body-parser';
import cors from 'cors';
dotenv.config();
const app: Express = express();
const port = process.env.PORT || 3000;
const apikey = ...;
const pathsToProxy = '/api/';
const MONGODB_URL = ...;
const corsOption = {
credentials: true,
origin: ['http://localhost:8080', 'http://localhost:3000'],
};
app.use(cors());
app.use(bodyParser.json());
app.all('/api/*', async (req: Request, res: Response) => {
const url = req.url.replace(pathsToProxy, MONGODB_URL);
let headers = new Headers();
headers.set('Content-Type', req.get('content-type') || 'application/json');
headers.set('Accept', req.get('accept') || 'application/json');
headers.set('apiKey', apikey!);
const mongoReq = {
method: req.method,
headers: headers,
body: ['PUT', 'POST'].includes(req.method)
? JSON.stringify(req.body)
: undefined,
};
try {
const mongoRes = await fetch(url, mongoReq);
mongoRes.body?.pipeTo(
new WritableStream({
start() {
res.statusCode = mongoRes.status;
mongoRes.headers.forEach((v, n) => res.setHeader(n, v));
},
write(chunk) {
res.write(chunk);
},
close() {
res.end();
},
})
);
} catch (e) {
console.log(e);
res.status(500).send(e);
}
});
app.listen(port, () => {
console.log(`[server]: Server is running at http://localhost:${port}`);
});
我在这里没有看到任何明显会导致输出被截断的东西。
为什么不简单地使用标准
.json()
我没有看到将从 mongodb 代理返回的数据作为整个数据进行分块的逻辑原因。
所以试试这个: try {
const mongoRes = await fetch(url, mongoReq);
const status = mongoRes.status;
const body = await mongoRes.json();
res.set({
...mongoRes.headers,
});
res
.status(mongoRes.status)
.json(body);
}
catch (error) {
console.error(error);
res
.status(500)
.json({
message: error.message,
});
}