Nginx 作为 Dart 服务器的代理未通过 POST 请求 body
Nginx as proxy for Dart server does not pass POST request body
我有一个用 Dart 实现的服务器,想解析 POST 请求 body。我正在使用 Postman / curl(和 Flutter 应用程序)来测试服务器。当我使用 localhost
访问服务器时,POST 请求 body 被正确处理并且服务器按预期工作。但是,当我尝试使用域名和 Nginx 作为反向代理处理来访问它时,服务器在尝试处理请求时崩溃 body.
使用相同的 nginx 配置,但 NodeJS 作为服务器(在其他项目中)带有 body-parser
包,NodeJS 服务器能够读取 body.
请求的curl
版本:
curl --location --request POST 'https://insanichess.com/api/auth/register' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
"email": "test@stelynx.com",
"password": "test_pwd"
}'
Nginx 配置文件(使用 Certbot 生成):
server {
server_name insanichess.com www.insanichess.com;
location / {
proxy_pass http://localhost:4040;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
listen [::]:443 ssl; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/insanichess.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/insanichess.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}server {
if ($host = www.insanichess.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = insanichess.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name insanichess.com www.insanichess.com;
return 404; # managed by Certbot
}
Dart代码的重要部分:
// insanichess_server.dart
/// Starts the server.
Future<void> start() async {
final InternetAddress address = InternetAddress.loopbackIPv4;
final int port =
int.parse(Platform.environment['INSANICHESS_PORT'] ?? '4040');
final HttpServer server = await HttpServer.bind(address, port);
_logger.info('InsanichessServer.create', 'Server listening on port $port');
await _handleRequests(onServer: server);
}
/// Passes every request [onServer] to [_router].
Future<void> _handleRequests({required HttpServer onServer}) async {
await for (final HttpRequest request in onServer) {
await _router.handle(request);
}
}
// auth_controller.dart
Future<void> handleRegistration(HttpRequest request) async {
if (request.method != 'POST' ||
request.contentLength <= 0 ||
request.headers.contentType?.value != ContentType.json.value) {
return respondWithBadRequest(request);
}
final String content = await utf8.decodeStream(request);
final Map<String, dynamic> body = jsonDecode(content);
//...
}
服务器崩溃
Unhandled exception:
FormatException: Unexpected end of input (at character 1)
^
#0 _ChunkedJsonParser.fail (dart:convert-patch/convert_patch.dart:1405:5)
#1 _ChunkedJsonParser.close (dart:convert-patch/convert_patch.dart:523:7)
#2 _parseJson (dart:convert-patch/convert_patch.dart:41:10)
#3 JsonDecoder.convert (dart:convert/json.dart:506:36)
#4 JsonCodec.decode (dart:convert/json.dart:157:41)
#5 jsonDecode (dart:convert/json.dart:96:10)
#6 AuthController.handleRegistration (package:insanichess_server/src/controller/api/auth/auth.dart:79:39)
<asynchronous suspension>
#7 ApiRouter.handle (package:insanichess_server/src/router/api/api.dart:29:16)
<asynchronous suspension>
#8 ICRouter.handle (package:insanichess_server/src/router/ic_router.dart:27:16)
<asynchronous suspension>
#9 InsanichessServer._handleRequests (package:insanichess_server/src/insanichess_server.dart:38:7)
<asynchronous suspension>
#10 InsanichessServer.start (package:insanichess_server/src/insanichess_server.dart:32:5)
<asynchronous suspension>
#11 main (file:///home/campovski/insanichess/server/bin/main.dart:17:3)
<asynchronous suspension>
我尝试按照类似 Whosebug 答案中的建议在 nginx 中设置 CORS 和 X-** headers,但错误始终相同。 x-www-form-urlencoded
版本也没有帮助。
在 jsonDecode
之前打印 content.length
给出 0,但是在处理程序中打印 Content-Length
header 值给出正确的值(我认为它是 63 或其他)。
这是处理程序在请求中收到的所有 header:
user-agent: curl/7.64.1
content-type: application/json; charset=utf-8
connection: upgrade
accept: */*
content-length: 63
host: insanichess.com
我假设问题出在使用 nginx 进行代理,因为直接在本地主机上查询是有效的,但是几乎相同的设置与 NodeJS 作为后端一起工作似乎很奇怪。该项目的完整源代码可在 GitHub 上找到,以备不时之需。
好像有问题
final Map<String, dynamic> body = jsonDecode(content);
或在 NGINX 上具有重定向状态。您应该使用 307 响应代码。 Source
出于某种原因,从 nginx 配置中的 location /
块中删除除 proxy_pass
之外的所有内容都有帮助。这个配置现在可以了:
server {
server_name insanichess.com www.insanichess.com;
location / {
proxy_pass http://localhost:4040;
}
listen [::]:443 ssl; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/insanichess.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/insanichess.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}server {
if ($host = www.insanichess.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = insanichess.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name insanichess.com www.insanichess.com;
return 404; # managed by Certbot
}
我有一个用 Dart 实现的服务器,想解析 POST 请求 body。我正在使用 Postman / curl(和 Flutter 应用程序)来测试服务器。当我使用 localhost
访问服务器时,POST 请求 body 被正确处理并且服务器按预期工作。但是,当我尝试使用域名和 Nginx 作为反向代理处理来访问它时,服务器在尝试处理请求时崩溃 body.
使用相同的 nginx 配置,但 NodeJS 作为服务器(在其他项目中)带有 body-parser
包,NodeJS 服务器能够读取 body.
请求的curl
版本:
curl --location --request POST 'https://insanichess.com/api/auth/register' \
--header 'Content-Type: application/json; charset=utf-8' \
--data-raw '{
"email": "test@stelynx.com",
"password": "test_pwd"
}'
Nginx 配置文件(使用 Certbot 生成):
server {
server_name insanichess.com www.insanichess.com;
location / {
proxy_pass http://localhost:4040;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
listen [::]:443 ssl; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/insanichess.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/insanichess.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}server {
if ($host = www.insanichess.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = insanichess.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name insanichess.com www.insanichess.com;
return 404; # managed by Certbot
}
Dart代码的重要部分:
// insanichess_server.dart
/// Starts the server.
Future<void> start() async {
final InternetAddress address = InternetAddress.loopbackIPv4;
final int port =
int.parse(Platform.environment['INSANICHESS_PORT'] ?? '4040');
final HttpServer server = await HttpServer.bind(address, port);
_logger.info('InsanichessServer.create', 'Server listening on port $port');
await _handleRequests(onServer: server);
}
/// Passes every request [onServer] to [_router].
Future<void> _handleRequests({required HttpServer onServer}) async {
await for (final HttpRequest request in onServer) {
await _router.handle(request);
}
}
// auth_controller.dart
Future<void> handleRegistration(HttpRequest request) async {
if (request.method != 'POST' ||
request.contentLength <= 0 ||
request.headers.contentType?.value != ContentType.json.value) {
return respondWithBadRequest(request);
}
final String content = await utf8.decodeStream(request);
final Map<String, dynamic> body = jsonDecode(content);
//...
}
服务器崩溃
Unhandled exception:
FormatException: Unexpected end of input (at character 1)
^
#0 _ChunkedJsonParser.fail (dart:convert-patch/convert_patch.dart:1405:5)
#1 _ChunkedJsonParser.close (dart:convert-patch/convert_patch.dart:523:7)
#2 _parseJson (dart:convert-patch/convert_patch.dart:41:10)
#3 JsonDecoder.convert (dart:convert/json.dart:506:36)
#4 JsonCodec.decode (dart:convert/json.dart:157:41)
#5 jsonDecode (dart:convert/json.dart:96:10)
#6 AuthController.handleRegistration (package:insanichess_server/src/controller/api/auth/auth.dart:79:39)
<asynchronous suspension>
#7 ApiRouter.handle (package:insanichess_server/src/router/api/api.dart:29:16)
<asynchronous suspension>
#8 ICRouter.handle (package:insanichess_server/src/router/ic_router.dart:27:16)
<asynchronous suspension>
#9 InsanichessServer._handleRequests (package:insanichess_server/src/insanichess_server.dart:38:7)
<asynchronous suspension>
#10 InsanichessServer.start (package:insanichess_server/src/insanichess_server.dart:32:5)
<asynchronous suspension>
#11 main (file:///home/campovski/insanichess/server/bin/main.dart:17:3)
<asynchronous suspension>
我尝试按照类似 Whosebug 答案中的建议在 nginx 中设置 CORS 和 X-** headers,但错误始终相同。 x-www-form-urlencoded
版本也没有帮助。
在 jsonDecode
之前打印 content.length
给出 0,但是在处理程序中打印 Content-Length
header 值给出正确的值(我认为它是 63 或其他)。
这是处理程序在请求中收到的所有 header:
user-agent: curl/7.64.1
content-type: application/json; charset=utf-8
connection: upgrade
accept: */*
content-length: 63
host: insanichess.com
我假设问题出在使用 nginx 进行代理,因为直接在本地主机上查询是有效的,但是几乎相同的设置与 NodeJS 作为后端一起工作似乎很奇怪。该项目的完整源代码可在 GitHub 上找到,以备不时之需。
final Map<String, dynamic> body = jsonDecode(content);
或在 NGINX 上具有重定向状态。您应该使用 307 响应代码。 Source
出于某种原因,从 nginx 配置中的 location /
块中删除除 proxy_pass
之外的所有内容都有帮助。这个配置现在可以了:
server {
server_name insanichess.com www.insanichess.com;
location / {
proxy_pass http://localhost:4040;
}
listen [::]:443 ssl; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/insanichess.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/insanichess.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}server {
if ($host = www.insanichess.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = insanichess.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name insanichess.com www.insanichess.com;
return 404; # managed by Certbot
}