将服务器重新定位到不同的 apache 服务器后,Dart http.MultipartRequest 未将数据发送到 Lumen,Postman 工作正常

JVE*_*999 5 apache nginx dart lumen flutter

我有一个多部分请求,正在尝试从我的 Flutter 应用程序发送到我的远程 Lumen/Apache 服务器。当我在 Homestead 本地托管 Lumen 服务器(运行 nginx)时,这段代码运行良好。

通过 Postman 发送请求时,Lumen 服务器本身会准确响应。我怀疑 Flutter 应用程序根本没有发送任何内容,因为它在服务器移动之前就在工作。由于它不是 Lumen 应用程序,因为它与 Postman 一起使用,所以我认为它与 apache 有关。

我设置的标题http.MultipartRequest()是(在我使用的 Postman 中form-data):

headers['Content-Type'] = 'multipart/form-data';
Run Code Online (Sandbox Code Playgroud)

我还有一个Authorization Bearer: token工作正常的标头,因为应用程序会在运行路线之前呈现未经授权的响应。

我有以下代码:

    ...
    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!');
Run Code Online (Sandbox Code Playgroud)

我在调试中得到以下输出:

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']
Run Code Online (Sandbox Code Playgroud)

在我的 Lumen 应用程序中,我有一个简单的函数:

    var_dump($request->all());
    die;
Run Code Online (Sandbox Code Playgroud)

我得到以下结果:

I/flutter ( 7073): array(1) {
I/flutter ( 7073):   ["_method"]=>
I/flutter ( 7073):   string(4) "POST"
I/flutter ( 7073): }
Run Code Online (Sandbox Code Playgroud)

这是由于请求未通过验证检查而产生的。在此之前,我有更长的功能:

 $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',
        ]);
Run Code Online (Sandbox Code Playgroud)

尽管数据显然正在发送(并且过去在服务器移动之前就通过了),但它未能通过验证测试。

原因可能是什么?似乎唯一的区别是从 nginx 本地 Homestead 服务器迁移到远程 apache 服务器。我想也许我需要一个不同的标题。

更新

经过更多测试,我发现如果 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)
Run Code Online (Sandbox Code Playgroud)

同样,如果没有附加文件(并且其他一切都相同),则正确形成的请求将起作用。就是当http请求有一个文件时,它突然出乎意料地工作。

在最后一个服务器中,我无法完全测试 http 功能,因为我使用 localtunnel.js 将请求从 Homestead 转发到我的手机,但它有一个我不想使用的文件大小限制。然而,我确实知道 darthttp正在发送文件,因为413 Request Entity Too Large没有图像就不会发生响应。

这是 Flutter 的 DevTools 中请求对象的输出(抱歉,这是一张图片 - 它不允许选择文本):

请求对象

当不包含文件时,请求看起来相同,只是文件列表为空。尽管如此,没有文件的请求会被服务器接收到带有数据的请求,而其他请求显然不会发送任何数据。

请求对象的 headers 字段看起来也很好,Content-Type存在。授权字段显然也有效,否则我会收到未经授权的错误。由于请求对象看起来不错,request.send();如果附加了文件,Lumen 应用程序之间的某些东西就会删除所有数据。它来自哪里——Flutter 应用程序还是服务器——很难确定。(考虑到当我使用 localtunnel.js 时附加文件时,Flutter 应用程序肯定会发送较大的内容,它似乎可能在服务器端,因为 Flutter 应用程序似乎正在发送数据,只是服务器在以下情况下会丢弃它:有一个文件。但是,Postman 工作时没有打嗝,这表明服务器运行正常。)

更新

我的回答有点早了。由于文件太大,PHP 丢弃了所有数据。为post_max_size和编辑 php.ini 后upload_max_filesize,数据确实开始通过,起初,我认为这表明它正在工作。

然而,事实证明,虽然现在非文件数据正在通过,并且使用mod_dumpio,我看到文件正在发送,但当请求来自 Flutter 时http.multipartRequest,服务器正在删除该文件。当邮递员发出请求时,一切正常。我也确保使用完全相同的图像进行测试,并且请求似乎没有差异。

小智 1

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

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