Dart http.MultipartRequest 将服务器重新定位到不同的 apache 服务器后未向 Lumen 发送数据,Postman 工作正常
Dart http.MultipartRequest not sending data to Lumen after relocating server to a different apache server, Postman works fine
我有一个多部分请求,我正试图从我的 Flutter 应用程序发送到我的远程 Lumen/Apache 服务器。当我在 Homestead 本地托管运行 nginx 的 Lumen 服务器时,这段代码运行良好。
当通过 Postman 发送请求时,Lumen 服务器本身会准确响应。我怀疑 Flutter 应用程序根本没有发送任何内容,因为它在服务器移动之前一直在工作。由于它不是 Lumen 应用程序,因为它与 Postman 一起使用,所以我认为它与 apache 有关。
我设置的header,使用http.MultipartRequest()
是(在Postman中我使用form-data
):
headers['Content-Type'] = 'multipart/form-data';
我还有一个 Authorization Bearer: token
header 可以正常工作,因为该应用程序会在 运行 路由之前显示未经授权的响应。
我有以下代码:
...
print("Multipart request fields: " + request.fields.toString());
print("Multipart request files: " + request.files.toString());
var streamedResponse = await request.send();
response = await http.Response.fromStream(streamedResponse);
if (response.statusCode == 200) print('Uploaded!');
我在调试中得到以下输出:
I/flutter ( 7073): Multipart request fields: {productName: new, description: new, price: 30.0, currency: USD, quantity: -1.0, mass: 0.0, massUnit: lb, isData: true}
I/flutter ( 7073): Multipart request files: [Instance of 'MultipartFile']
在我的 Lumen 应用程序中,我有一个简单的功能:
var_dump($request->all());
die;
我得到以下结果:
I/flutter ( 7073): array(1) {
I/flutter ( 7073): ["_method"]=>
I/flutter ( 7073): string(4) "POST"
I/flutter ( 7073): }
这是来自未通过验证检查的请求。在此之前,我有更长的功能:
$validator = Validator::make($request->all(), [
'productName' => 'required',
'description' => 'required',
'image' => 'sometimes|image|mimetypes:image/jpeg,image/png|max:600',// TODO remove sometimes from this
'price' => 'required',
'currency' => 'required|string',
'quantity' => 'required',
'mass' => 'numeric',
'massUnit' => 'required|string',
'isData' => 'present|string|nullable',
]);
并且它没有通过验证测试,即使数据显然正在发送(并且它曾经在服务器移动之前通过)。
可能是什么原因?似乎唯一的区别是从 nginx 本地 Homestead 服务器移动到远程 apache 服务器。我想也许我需要一个不同的 header,可能。
更新
通过更多测试,我发现如果 multipart/form-data 请求中没有图像,请求也可以正常工作。该问题似乎取决于附加文件。显然,当且仅当有附加文件时,服务器报告没有发送数据。
我有两个非常相似的请求,一个是 POST,一个是 PATCH。我发现对于 Postman,使用作为 PATCH 的请求,将其作为 PATCH 请求发送会导致同样的问题——没有发送数据。但是,将其作为 POST 请求发送,并将字段“_method”设置为“PATCH”确实有效。当设置为 POST 请求时,作为 POST 请求(添加新项目)的请求在没有“_method”字段的情况下工作正常。
POST 端点正在响应,就好像 http
没有发送“POST”请求(空数据)。对于 PATCH 端点,Lumen 的响应就像是一个“POST”请求。
这是 Postman 和 http.MultipartRequest
的区别:
With POST request:
Postman: POST request + "_method: POST": Works
http: POST request + "_method: POST": No data sent
With PATCH request:
Postman: POST request + "_method: PATCH": Works
Postman: PATCH request without "_method": No data sent
http: POST request + "_method: PATCH": 405 Method Not Allowed (as if it was a PATCH request)
同样,如果没有附加文件(其他一切都一样),正确格式的请求也有效。就是当http请求有文件的时候,突然出乎意料。
在上一个服务器中,我无法完全测试 http 功能,因为我使用 localtunnel.js 将请求从 Homestead 转发到我的 phone,但它有一个文件大小我不想使用的限制。我确实知道 dart 的 http
正在发送文件,但是,由于 413 Request Entity Too Large
响应在没有图像的情况下不会发生。
这是 Flutter 的 DevTools 中请求 object 的输出(抱歉,这是一张图片 - 它不允许选择文本):
当不包含文件时,除了文件列表为空之外,请求看起来完全相同。尽管如此,没有文件的请求会被服务器接收到数据,而另一个结果显然没有发送数据。
请求 object 的 headers 字段看起来也不错,存在 Content-Type
。授权字段显然也有效,否则我会遇到未经授权的错误。由于请求 object 看起来不错,如果有附加文件,request.send();
和 Lumen 应用程序之间的某些东西会丢弃所有数据。它来自哪里——Flutter 应用程序或服务器——很难确定。 (考虑到当我使用 localtunnel.js 附加文件时,Flutter 应用程序肯定会发送 一些大的东西 ,这似乎是在服务器端,因为它似乎是 Flutter应用程序正在发送数据,如果有文件,只是服务器正在丢弃它。但是,Postman 工作没有打嗝,这表明服务器运行正常。)
更新
我的回答有点早。 PHP 由于文件太大而丢弃了所有数据。在为 post_max_size
和 upload_max_filesize
编辑 php.ini 之后,数据确实开始通过了,起初,我认为这表明它正在工作。
然而,事实证明,虽然现在 non-file 数据正在通过,并使用 mod_dumpio
,但当请求来自 Flutter 的 http.multipartRequest
,服务器正在删除文件。当请求来自 Postman 时,一切正常。我也确保使用完全相同的图像进行测试,并且请求似乎没有差异。
更新:这个答案只解决了部分问题。
在服务器上使用tcpdump
,发现服务器确实在接收数据(虽然Lumen说的是没有接收数据),而且数据量好像和文件是否有对应附与不附。由此看来,问题似乎出在 Apache、PHP 或 Lumen 上。
我还启用了 mod_dumpio
,并测试了带文件和不带文件的请求,两者似乎都可以正常发送数据。文件请求显然发送了更多的数据,Content-Length
报告似乎是准确的,即使 Lumen 没有报告任何数据。
通过 error.log
排序,但我确实发现了错误。只是 PHP 正在丢弃数据,因为它超过了 post_max_size
8MB 的大小。编辑 php.ini
和 upload_max_filesize
后,应用程序运行良好。
有趣的是,这通常是文件上传和 PHP 服务器发生的第一个错误,所以很奇怪我没有怀疑它。如果 PHP 默认发出 413
响应就好了。
最近我在 MongoDB/HapiJS 服务器上将 MultipartFile 发送到我们的服务器。虽然它在 postman 和 vue web app 中工作,但我在 Flutter 上挣扎以找出它不起作用的原因。
在我们的例子中,解决方案相当愚蠢,但它有效:
发送文件时,我使用 MultipartFile.fromBytes(byteData),将其更改为 MultipartFile.fromFile(filePath) 后,它起作用了.
你能检查一下(或其他方法)并判断它是否有效吗?
我有一个多部分请求,我正试图从我的 Flutter 应用程序发送到我的远程 Lumen/Apache 服务器。当我在 Homestead 本地托管运行 nginx 的 Lumen 服务器时,这段代码运行良好。
当通过 Postman 发送请求时,Lumen 服务器本身会准确响应。我怀疑 Flutter 应用程序根本没有发送任何内容,因为它在服务器移动之前一直在工作。由于它不是 Lumen 应用程序,因为它与 Postman 一起使用,所以我认为它与 apache 有关。
我设置的header,使用http.MultipartRequest()
是(在Postman中我使用form-data
):
headers['Content-Type'] = 'multipart/form-data';
我还有一个 Authorization Bearer: token
header 可以正常工作,因为该应用程序会在 运行 路由之前显示未经授权的响应。
我有以下代码:
...
print("Multipart request fields: " + request.fields.toString());
print("Multipart request files: " + request.files.toString());
var streamedResponse = await request.send();
response = await http.Response.fromStream(streamedResponse);
if (response.statusCode == 200) print('Uploaded!');
我在调试中得到以下输出:
I/flutter ( 7073): Multipart request fields: {productName: new, description: new, price: 30.0, currency: USD, quantity: -1.0, mass: 0.0, massUnit: lb, isData: true}
I/flutter ( 7073): Multipart request files: [Instance of 'MultipartFile']
在我的 Lumen 应用程序中,我有一个简单的功能:
var_dump($request->all());
die;
我得到以下结果:
I/flutter ( 7073): array(1) {
I/flutter ( 7073): ["_method"]=>
I/flutter ( 7073): string(4) "POST"
I/flutter ( 7073): }
这是来自未通过验证检查的请求。在此之前,我有更长的功能:
$validator = Validator::make($request->all(), [
'productName' => 'required',
'description' => 'required',
'image' => 'sometimes|image|mimetypes:image/jpeg,image/png|max:600',// TODO remove sometimes from this
'price' => 'required',
'currency' => 'required|string',
'quantity' => 'required',
'mass' => 'numeric',
'massUnit' => 'required|string',
'isData' => 'present|string|nullable',
]);
并且它没有通过验证测试,即使数据显然正在发送(并且它曾经在服务器移动之前通过)。
可能是什么原因?似乎唯一的区别是从 nginx 本地 Homestead 服务器移动到远程 apache 服务器。我想也许我需要一个不同的 header,可能。
更新
通过更多测试,我发现如果 multipart/form-data 请求中没有图像,请求也可以正常工作。该问题似乎取决于附加文件。显然,当且仅当有附加文件时,服务器报告没有发送数据。
我有两个非常相似的请求,一个是 POST,一个是 PATCH。我发现对于 Postman,使用作为 PATCH 的请求,将其作为 PATCH 请求发送会导致同样的问题——没有发送数据。但是,将其作为 POST 请求发送,并将字段“_method”设置为“PATCH”确实有效。当设置为 POST 请求时,作为 POST 请求(添加新项目)的请求在没有“_method”字段的情况下工作正常。
POST 端点正在响应,就好像 http
没有发送“POST”请求(空数据)。对于 PATCH 端点,Lumen 的响应就像是一个“POST”请求。
这是 Postman 和 http.MultipartRequest
的区别:
With POST request:
Postman: POST request + "_method: POST": Works
http: POST request + "_method: POST": No data sent
With PATCH request:
Postman: POST request + "_method: PATCH": Works
Postman: PATCH request without "_method": No data sent
http: POST request + "_method: PATCH": 405 Method Not Allowed (as if it was a PATCH request)
同样,如果没有附加文件(其他一切都一样),正确格式的请求也有效。就是当http请求有文件的时候,突然出乎意料。
在上一个服务器中,我无法完全测试 http 功能,因为我使用 localtunnel.js 将请求从 Homestead 转发到我的 phone,但它有一个文件大小我不想使用的限制。我确实知道 dart 的 http
正在发送文件,但是,由于 413 Request Entity Too Large
响应在没有图像的情况下不会发生。
这是 Flutter 的 DevTools 中请求 object 的输出(抱歉,这是一张图片 - 它不允许选择文本):
当不包含文件时,除了文件列表为空之外,请求看起来完全相同。尽管如此,没有文件的请求会被服务器接收到数据,而另一个结果显然没有发送数据。
请求 object 的 headers 字段看起来也不错,存在 Content-Type
。授权字段显然也有效,否则我会遇到未经授权的错误。由于请求 object 看起来不错,如果有附加文件,request.send();
和 Lumen 应用程序之间的某些东西会丢弃所有数据。它来自哪里——Flutter 应用程序或服务器——很难确定。 (考虑到当我使用 localtunnel.js 附加文件时,Flutter 应用程序肯定会发送 一些大的东西 ,这似乎是在服务器端,因为它似乎是 Flutter应用程序正在发送数据,如果有文件,只是服务器正在丢弃它。但是,Postman 工作没有打嗝,这表明服务器运行正常。)
更新
我的回答有点早。 PHP 由于文件太大而丢弃了所有数据。在为 post_max_size
和 upload_max_filesize
编辑 php.ini 之后,数据确实开始通过了,起初,我认为这表明它正在工作。
然而,事实证明,虽然现在 non-file 数据正在通过,并使用 mod_dumpio
,但当请求来自 Flutter 的 http.multipartRequest
,服务器正在删除文件。当请求来自 Postman 时,一切正常。我也确保使用完全相同的图像进行测试,并且请求似乎没有差异。
更新:这个答案只解决了部分问题。
在服务器上使用tcpdump
,发现服务器确实在接收数据(虽然Lumen说的是没有接收数据),而且数据量好像和文件是否有对应附与不附。由此看来,问题似乎出在 Apache、PHP 或 Lumen 上。
我还启用了 mod_dumpio
,并测试了带文件和不带文件的请求,两者似乎都可以正常发送数据。文件请求显然发送了更多的数据,Content-Length
报告似乎是准确的,即使 Lumen 没有报告任何数据。
通过 error.log
排序,但我确实发现了错误。只是 PHP 正在丢弃数据,因为它超过了 post_max_size
8MB 的大小。编辑 php.ini
和 upload_max_filesize
后,应用程序运行良好。
有趣的是,这通常是文件上传和 PHP 服务器发生的第一个错误,所以很奇怪我没有怀疑它。如果 PHP 默认发出 413
响应就好了。
最近我在 MongoDB/HapiJS 服务器上将 MultipartFile 发送到我们的服务器。虽然它在 postman 和 vue web app 中工作,但我在 Flutter 上挣扎以找出它不起作用的原因。 在我们的例子中,解决方案相当愚蠢,但它有效: 发送文件时,我使用 MultipartFile.fromBytes(byteData),将其更改为 MultipartFile.fromFile(filePath) 后,它起作用了.
你能检查一下(或其他方法)并判断它是否有效吗?