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_sizeupload_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.iniupload_max_filesize 后,应用程序运行良好。

有趣的是,这通常是文件上传和 PHP 服务器发生的第一个错误,所以很奇怪我没有怀疑它。如果 PHP 默认发出 413 响应就好了。

最近我在 MongoDB/HapiJS 服务器上将 MultipartFile 发送到我们的服务器。虽然它在 postman 和 vue web app 中工作,但我在 Flutter 上挣扎以找出它不起作用的原因。 在我们的例子中,解决方案相当愚蠢,但它有效: 发送文件时,我使用 MultipartFile.fromBytes(byteData),将其更改为 MultipartFile.fromFile(filePath) 后,它起作用了.

你能检查一下(或其他方法)并判断它是否有效吗?