【问题标题】:PATCH and PUT Request Does not Working with form-dataPATCH 和 PUT 请求不适用于表单数据
【发布时间】:2018-06-05 04:15:05
【问题描述】:

我正在使用 Laravel 创建一个 RESTFUL 应用程序,并使用 Postman 测试该应用程序。目前,PATCHPUT 如果从 Postman 发送的数据带有 form-data,则会出现问题。

// Parameter `{testimonial}` will be sent to backend.
Route::post  ('testimonials/{testimonial}', 'TestimonialController@update');

// Parameter `{testimonial}` will not be sent to backend (`$request->all()` will be empty) if sent from Postman with form-data.
Route::patch ('testimonials/{testimonial}', 'TestimonialController@update');
Route::put   ('testimonials/{testimonial}', 'TestimonialController@update');
  • 使用表单数据,$request->all() 可以用于POST
  • 使用 x-www-form-urlencoded、$request->all() 可以用于 PATCHPUTPOST
  • 但是,如果我从 Postman 发送带有表单数据的 PUTPATCH,则 $request->all() 将为空(参数不会发送到后端)。

目前的解决方案是使用POST 更新模型。我想知道为什么 PATCHPUT 在使用 Postman 的表单数据发送时不起作用。

【问题讨论】:

标签: php laravel http postman


【解决方案1】:

这是一个已知问题,根据以下 Github comment 的解决方法建议是,在发送 PATCH / PUT 请求时,您应该执行以下操作:

您应该发送 POST 并将 _method 设置为 PUT(与发送表单相同)以使您的文件可见

所以基本上你发送一个带有参数的 POST 请求,该参数设置实际方法,Laravel 似乎明白这一点。

根据documentation

由于 HTML 表单无法发出 PUTPATCHDELETE 请求,因此您需要添加一个隐藏的 _method 字段来欺骗这些 HTTP 动词。 @method Blade 指令可以为你创建这个字段:

<form action="/foo/bar" method="POST">
    @method('PUT')

    ...
</form> 

或者,您可以使用method_field 辅助函数来执行上述操作:

method_field 函数生成一个 HTML 隐藏输入字段,其中包含表单的 HTTP 动词的欺骗值。例如,使用 Blade 语法:

<form method="POST">
    {{ method_field('PUT') }}
</form>

【讨论】:

  • 我正在制作 RESTFUL 应用
  • 我不明白这将如何改变它是一个已知问题的事实?你需要以不同的方式去做。它是如此简单。它可能不是您想要的理想答案,但它是给定的答案。
【解决方案2】:

我在这篇文章中学习了如何解决这个问题,我想分享一下我做了什么。

下图是我如何设置 Postman 发送 HTTP POST 请求并进入 PUT 请求并使其接收我的文件。

我不确定这是否是执行 RESTFul API 的正确方法。 但效果很好

【讨论】:

  • 在我的情况下 _method=PUT 不起作用,但 _method=PATCH 工作正常
【解决方案3】:

所以正如上面提到的每个人并解释了一切,但我仍然没有看到使用 REST API 时案例的答案,所以我放弃了@Caique Andrade 的答案并发送了一个 POST 请求并形成了我的 URL 链接,如下所示:

url = 'https://yourwebsite.com/api/v1/users/$id?_method=PUT';

$id是用户的变量id。

?_method=PUT 被添加到 url POST 请求中以欺骗请求并且它可以工作

在我的例子中,我在 Flutter 中使用了 Dart,并使用 Http 包发送了一个 post 请求,Laravel 将该 POST 请求作为 PUT 请求捕获

【讨论】:

  • 当我使用这种方法时,我得到一个 403 代码。有什么建议吗?需要在后端更新一些东西吗?
  • 您可能没有设置正确,创建一个问题并提供您的代码,以便我们帮助您解决它,此方法在 laravel 7 项目中完美运行
  • 谢谢@RidhaRezzag,这对于具有多个图像的 Laravel 8 表单数据非常有用,并且放置了 ajax 调用。
【解决方案4】:

Laravel PATCH 和 PUT 方法不适用于 form-data,它是 Symfony 甚至 PHP 的已知问题(Google 对此 - Laravel 使用许多 Symfony 基础包,包括 Request)。

  1. 如果您不需要通过请求传递文件,请将 form-data 更改为 raw 并使用 json 内容类型。例如:{"name":"changed"}。它将被读取为php://input,您的代码应该可以正常工作($request-&gt;all() 现在是["name" =&gt; "changed])。

  2. 如果您需要传递文件,在我看来,请勿在 REST API 方法中传递它。您可以编写另一种方法来对文件执行任何操作(例如:POST form-data -> 上传文件 -> 更新 db -> 返回文件路径/url/甚至它的 base64 内容),然后您可以使用它输出/结果以继续使用您的补丁/放置方法(raw 带有 json 内容类型)。当我在 API 中处理文件时,我总是这样做。

希望对您有所帮助!

【讨论】:

  • 如果我将PATCHPUT 改为POST 会怎样?这是一个好习惯吗?
  • 这取决于你。但是,我们应该为 REST API 使用约定。 POST 创建新的,PATCHPUT 更新,DELETE 删除...抱歉回复晚了。超级晚。 :D
【解决方案5】:

如前所述,这不是 symfony(或 laravel 或任何其他框架)的问题,而是 PHP 的限制。

在浏览了几个关于 php 核心的 RFC 之后,核心开发团队似乎有点反对实施与现代化 HTTP 请求处理有关的任何事情。该问题于 2011 年首次报告,看起来与拥有原生解决方案没有任何关系。

也就是说,我设法找到了this PECL extension。我对 pecl 不是很熟悉,而且似乎无法使用 pear 让它工作。但我使用的是 CentOS 和 Remi PHP,它们有一个 yum 包。

我运行了yum install php-pecl-apfd,它立即解决了这个问题(好吧,我不得不重新启动我的 docker 容器,但这是给定的)。

也就是说,request-&gt;all()files-&gt;get() 再次开始使用 multipart/form-data 处理 PATCH 和 PUT 请求。

我相信在各种风格的 linux 中还有其他包,我相信任何对 pear/pecl/general php 扩展有更多了解的人都可以让它在 windows 或 mac 上运行而没有问题。

【讨论】:

    【解决方案6】:

    正如@DazBaldwin 所说,这是一个 php 限制,可以解决安装 apfd 扩展的问题。 在windows上只需根据你的系统设置下载dll文件here并将php_apfd.dll放在path-to-php/ext目录最后放入extension= apfd 在 php.ini 文件中。

    它在 Windows 上对我有用。

    【讨论】:

      【解决方案7】:

      InertiaJS 解决方案

      我遇到了同样的问题。当没有发送文件时,一切正常,但是当我发送文件时,没有一个字段进入后端。

      这似乎是一个PHP的限制,通过put接收不到文件,如前所述。

      因此,对于那些使用 InertiaJS 的人,您需要进行 post - 而不是 put - 调用并将 _method: "put" 添加到您的惯性表单中,如下所示:

      updateForm: this.$inertia.form({
                  _method: "put",
                  "other fields"
              }),
      

      您的控制器会像 PUT 调用一样理解它,但后端可以访问文件。

      来源: https://inertiajs.com/manual-visits#method

      【讨论】:

      • 这个问题快把我逼疯了!非常感谢您的提示!
      【解决方案8】:

      我希望现在还为时不晚,或者如果有人正在寻求有关 JavaScript 的 FormData 接口的帮助。这是解决方案, 在 Laravel 中,您可以使用上面的 @script47 答案,对于正常的 Ajax 请求,您可以像这样附加数据,(PS:我使用相同的表单进行添加和更新,所以这是我的代码)

      let _url = '';
      let _type = 'POST';
      let _formData = new FormData(this);
      if(user_id == '' || user_id == null){
          _url = "{{ route('users.store') }}";
      }else{
          _url = "{{ route('users.update', ':id') }}";
          _url = _url.replace(':id', user_id);
          _formData.append('_method', 'PUT');
          // _type = 'PUT';
      }
      

      【讨论】:

      • 帮助很大,谢谢
      【解决方案9】:

      表单媒体类型没有为 PATCH 定义任何语义,因此使用它们确实是个坏主意(请参阅https://www.rfc-editor.org/errata/eid3169)。

      对于 PUT,预期的行为是仅存储表单编码的有效负载(以该格式)。这真的是你想要的吗?

      【讨论】:

        【解决方案10】:

        如果你的路由方法是 Patch 并使用 Postman 进行 Api 请求

        如果要发送文件,对于控制器来说,使用postman时,必须将发送方式设置为post方法,并在form-data部分 键=_方法 值 = 补丁 您不必设置文件,以便在发送请求时不会遇到任何错误。

        【讨论】:

          【解决方案11】:

          您还可以在控制器中创建自定义函数来更新产品,然后创建 api 路由。

            public function updateTestimonial($id, Request $request) {
              $testimonial = Testimonial::where('id', '=', $id)->first();
              //update logic
          }
          

          API 路由

          Route::post('updatetestimonial/{id}', 'Testimonial@updateTestimonial');
          

          使用发布请求并传递推荐 ID。

          submitForm() {
                  let data = new FormData();
                  data.append('id', this.testtimonial.id);
                  data.append('description', this.testtimonial.description);
                  axios.post("/api/updatetestimonial/" + this.testimonial.id , data, {
                      headers: {
                          'accept': 'application/json',
                          'Accept-Language': 'en-US,en;q=0.8',
                          'Content-Type': 'multipart/form-data',
                      }
                  }).then(({ data }) => {
                       console.log("success");
                  });
              },
          

          【讨论】:

            【解决方案12】:

            您可以使用 post 方法。 常量形式 = 新 只需附加 form.append('_method', 'PATCH');

            【讨论】:

            • 给我们更多细节
            猜你喜欢
            • 2017-10-04
            • 1970-01-01
            • 1970-01-01
            • 2017-06-16
            • 2019-08-02
            • 2019-04-11
            • 1970-01-01
            • 2014-04-24
            相关资源
            最近更新 更多