为什么我没有看到 nodejs `response.addTrailers` 添加的 headers
Why am I not seeing the headers added by nodejs `response.addTrailers`
编辑
我已经能够使用 curl 直接联系后端,它肯定会发送尾随 header。它似乎在 body 之后的输出流中,所以我的 api 例程可能需要稍后检查它,或者它可能无法通过 nginx。
第二次编辑
我使用 curl 直接访问后端我看到尾随 header。联系前端(Nginx)我没看到
原始问题
我正在尝试创建一个节点服务器来响应来自客户端的 API 请求。
此服务器是由 nginx 代理的后端,它可能正在剥离 headers 但是...
这是它的反向代理配置,所以我不这么认为
location /api/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://localhost:2040;
proxy_redirect off;
proxy_buffering off;
proxy_cache off;
}
服务器正在处理这样的特定 api 请求
router.post('/api/process', async (req,res) => {
res.writeHead(200, {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache',
'X-Accel-Buffering': 'no',
'Trailer': 'API-Status'
});
try {
response = await callApiProcessor(req.params);
res.write(JSON.stringify(response));
res.addTrailers({'API-Status': 'OK'})
catch (e) {
res.addTrailers({'API-Status': e.toString()});
}
res.end();
});
在浏览器端,我正在使用这样的获取api
export default function api(url, params, signal) {
const options = {
credentials: 'same-origin',
method: 'post',
headers: new Headers({
'content-type': 'application/json'
}),
body: JSON.stringify(params)
};
if (signal) options.signal = signal;
return window.fetch('/api/' + url, options).then(response => {
if (!response.ok || response.headers['API-Status'] !== 'OK') {
if (response.ok) console.warn('SERVER API Error:', response.headers['API-Status']);
window.dispatchEvent(new LogoffRequest());
//put us back to home
window.history.pushState({}, null, '/');
window.dispatchEvent(new LocationAltered());
return {};
} else {
return response.json();
}
});
}
通过在 api 模块中放置断点,我在响应中看不到任何 header。因此,尽管 response.ok
是正确的,但我仍然在我的应用程序中强制客户端注销。
查看 Chrome 的 Dev Tools Networking 选项卡,我看不到 API-Status,尽管我确实看到了预告片 header。
正如我上面提到的,nginx 是拖车的片段。我在 nginx 邮件列表上问过这个问题,答案是它没有实现传递尾随 headers。但是,我已经解决了这个问题,即您如何在服务器中,在发送 header 后注意到一个问题(因为您已经开始发送 body)并传回本质上的内容403 或 500 服务器响应。
在服务器中,我有两个类似的例程 - 这是 500 错误之一,但 403 是相同的,除了状态代码和我记录客户端的 ip 地址 (req.headers['x-forwarded-for']
)。
function errored(req,res,message) {
debug('In "Errored"');
logger('error', `${message} with request url of ${req.originalUrl}`);
res.statusCode = 500;
res.end('---500---'); //definitely not json, so should cause api to throw even if attempt to send status code is to no avail.
}
如果在 body 导致发送 200 之前调用此方法,则会发送实际的 500,否则本质上应该是 json 的内容会被文本打断。
然后在客户端我有我的 api 调用函数:
import { ApiError } from "./events.js";
export default async function api(url, params, signal) {
const options = {
credentials: 'same-origin',
method: 'post',
headers: new Headers({
'content-type': 'application/json'
}),
body: JSON.stringify(params)
};
if (signal) options.signal = signal;
let text;
try {
const response = await window.fetch('/api/' + url, options);
if (!response.ok) throw new ApiError(response.status);
text = await response.text();
return JSON.parse(text);
} catch (err) {
if (err.type === 'api-error') throw err; //just
//we failed to parse the json - the actual code should be in the text near the end;
throw new ApiError(parseInt(text.substr(-6,3),10));
}
}
这会尝试请求,首先将其解析为文本(您只能读取 body 一次,所以我们将其作为文本进行,因此我们有一个副本,然后尝试将其解析为 JSON).如果最终解析抛出,或者响应拾取响应错误,我们可以确定是哪个抛出我的 ApiError 函数。在其他地方,我已将事件侦听器附加到未捕获的承诺拒绝
_promiseRejection(e) {
if (this.anError) return;
e.preventDefault();
const possibleError = e.reason;
let message
if (possibleError.type === 'api-error') {
this._serverError(possibleError)
} else {
const message = `Client Error: Uncaught Promise Rejection with reason ${e.reason} has occured`;
api('/session/log', { type: 'Error', message: message });
this.dispatchEvent(new SessionStatus({ type: 'error' }));
this.anError = true;
}
}
最后一个函数位于我的应用程序顶部的自定义元素中。大多数时候它的内容是隐藏的,但是当变量 this.anError
为真时它显示内容。我还有一些特殊事件可以在出现 403(但不是 500)的情况下注销用户,并在出现任何错误时切换到主页。
编辑
我已经能够使用 curl 直接联系后端,它肯定会发送尾随 header。它似乎在 body 之后的输出流中,所以我的 api 例程可能需要稍后检查它,或者它可能无法通过 nginx。
第二次编辑 我使用 curl 直接访问后端我看到尾随 header。联系前端(Nginx)我没看到
原始问题
我正在尝试创建一个节点服务器来响应来自客户端的 API 请求。
此服务器是由 nginx 代理的后端,它可能正在剥离 headers 但是... 这是它的反向代理配置,所以我不这么认为
location /api/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://localhost:2040;
proxy_redirect off;
proxy_buffering off;
proxy_cache off;
}
服务器正在处理这样的特定 api 请求
router.post('/api/process', async (req,res) => {
res.writeHead(200, {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache',
'X-Accel-Buffering': 'no',
'Trailer': 'API-Status'
});
try {
response = await callApiProcessor(req.params);
res.write(JSON.stringify(response));
res.addTrailers({'API-Status': 'OK'})
catch (e) {
res.addTrailers({'API-Status': e.toString()});
}
res.end();
});
在浏览器端,我正在使用这样的获取api
export default function api(url, params, signal) {
const options = {
credentials: 'same-origin',
method: 'post',
headers: new Headers({
'content-type': 'application/json'
}),
body: JSON.stringify(params)
};
if (signal) options.signal = signal;
return window.fetch('/api/' + url, options).then(response => {
if (!response.ok || response.headers['API-Status'] !== 'OK') {
if (response.ok) console.warn('SERVER API Error:', response.headers['API-Status']);
window.dispatchEvent(new LogoffRequest());
//put us back to home
window.history.pushState({}, null, '/');
window.dispatchEvent(new LocationAltered());
return {};
} else {
return response.json();
}
});
}
通过在 api 模块中放置断点,我在响应中看不到任何 header。因此,尽管 response.ok
是正确的,但我仍然在我的应用程序中强制客户端注销。
查看 Chrome 的 Dev Tools Networking 选项卡,我看不到 API-Status,尽管我确实看到了预告片 header。
正如我上面提到的,nginx 是拖车的片段。我在 nginx 邮件列表上问过这个问题,答案是它没有实现传递尾随 headers。但是,我已经解决了这个问题,即您如何在服务器中,在发送 header 后注意到一个问题(因为您已经开始发送 body)并传回本质上的内容403 或 500 服务器响应。
在服务器中,我有两个类似的例程 - 这是 500 错误之一,但 403 是相同的,除了状态代码和我记录客户端的 ip 地址 (req.headers['x-forwarded-for']
)。
function errored(req,res,message) {
debug('In "Errored"');
logger('error', `${message} with request url of ${req.originalUrl}`);
res.statusCode = 500;
res.end('---500---'); //definitely not json, so should cause api to throw even if attempt to send status code is to no avail.
}
如果在 body 导致发送 200 之前调用此方法,则会发送实际的 500,否则本质上应该是 json 的内容会被文本打断。
然后在客户端我有我的 api 调用函数:
import { ApiError } from "./events.js";
export default async function api(url, params, signal) {
const options = {
credentials: 'same-origin',
method: 'post',
headers: new Headers({
'content-type': 'application/json'
}),
body: JSON.stringify(params)
};
if (signal) options.signal = signal;
let text;
try {
const response = await window.fetch('/api/' + url, options);
if (!response.ok) throw new ApiError(response.status);
text = await response.text();
return JSON.parse(text);
} catch (err) {
if (err.type === 'api-error') throw err; //just
//we failed to parse the json - the actual code should be in the text near the end;
throw new ApiError(parseInt(text.substr(-6,3),10));
}
}
这会尝试请求,首先将其解析为文本(您只能读取 body 一次,所以我们将其作为文本进行,因此我们有一个副本,然后尝试将其解析为 JSON).如果最终解析抛出,或者响应拾取响应错误,我们可以确定是哪个抛出我的 ApiError 函数。在其他地方,我已将事件侦听器附加到未捕获的承诺拒绝
_promiseRejection(e) {
if (this.anError) return;
e.preventDefault();
const possibleError = e.reason;
let message
if (possibleError.type === 'api-error') {
this._serverError(possibleError)
} else {
const message = `Client Error: Uncaught Promise Rejection with reason ${e.reason} has occured`;
api('/session/log', { type: 'Error', message: message });
this.dispatchEvent(new SessionStatus({ type: 'error' }));
this.anError = true;
}
}
最后一个函数位于我的应用程序顶部的自定义元素中。大多数时候它的内容是隐藏的,但是当变量 this.anError
为真时它显示内容。我还有一些特殊事件可以在出现 403(但不是 500)的情况下注销用户,并在出现任何错误时切换到主页。