以HTML形式使用PUT方法


175

我可以在HTML表单中使用PUT方法将数据从表单发送到服务器吗?

Answers:



194

根据HTML标准,您不能这样做。方法属性的唯一有效值是getpost,它们对应于GET和POST HTTP方法。<form method="put">是无效的HTML,将被视为<form>,即发送GET请求。

取而代之的是,许多框架只是使用POST参数来隧道化HTTP方法:

<form method="post" ...>
  <input type="hidden" name="_method" value="put" />
...

当然,这需要服务器端解包。


3
您一直在链接草稿,而不是最终标准。只是要注意,稳定的HTML版本也不提供它。
hakre 2011年

13
@hakre HTML5已经是事实上的标准,并且可能会随着时间而发展。W3C所谓的“草稿”是经过至少3年的开发,在浏览器供应商的支持下,其投入超过99%,并且已经(至少在本部分和大多数非深奥部分中)得到了实现。他们都永远。但是,仅针对nitpicker,这是 HTML 4.01中的等效定义(W3C术语中的技术要求)。
phihag

请不要感到生气,我已经写过,这只是一个注释,其他HTML版本也不提供(XHTML 2稍有例外,但是现在已经过时了)。
hakre

1
@hakre放心,我一点都不生气。挑剔,我必须评论XHTML从技术上讲不是HTML,尽管可能会发现一两个相似之处;)
phihag 2011年

44

我可以在HTML表单中使用“放置”方法将数据从HTML表单发送到服务器吗?

是的,您可以,但是请记住,它不会导致PUT而是GET请求。如果您为标记的method属性使用无效值<form>,则浏览器将使用默认值get

HTML表单(最高HTML版本4(第5版草稿)和XHTML 1)仅支持GET和POST作为HTTP请求方法。一种解决方法是使用服务器读取的隐藏表单字段并相应地分派请求,从而通过POST隧道传输其他方法。XHTML 2.0曾经计划支持表单的GET,POST,PUT和DELETE,但是它正在纳入HTML5的XHTML5中,后者不打算支持PUT。[更新至]

您可以选择提供一个表单,但是不用提交表单,而可以使用带有JavaScript的PUT方法创建并触发XMLHttpRequest。



AJAX请求不能完全替换表单请求,因为表单请求会将用户重定向到给定的资源。例如,目前无法在浏览器中显示路线页面PUT /resource
JacopoStanchi

这样做是个坏主意。框架可以忽略PUT的表单参数。Java的HTTPServlet似乎如此。我们有一个错误,HttpRequest.getParameterMap()没有返回表单参数。
DaBlick

@DaBlick:但不是XMLHttpRequests吗?如果是这样,则依赖于访存API应该更加标准化。
hakre

27

_method 隐藏字段的解决方法

一些Web框架使用以下简单技术:

  • 将隐藏_method参数添加到非GET或POST的任何形式:

    <input type="hidden" name="_method" value="PUT">

    这可以通过HTML创建帮助器方法在框架中自动完成。

  • 将实际的表单方法固定为POST(<form method="post"

  • _method在服务器上进行处理,并且完全像发送该方法而不是实际的POST一样

您可以通过以下方式实现此目的:

  • 滑轨: form_tag
  • Laravel: @method("PATCH")

纯HTML不可能实现的原因/历史:https : //softwareengineering.stackexchange.com/questions/114156/why-there-are-no-put-and-delete-methods-in-html-forms


Laravel(php)通过使用@method("PATCH")
santiago arizti,

这似乎是一个合理的解决方法,但仍然很不幸,因为它使调试变得困难。例如,如果您需要检查服务器日志或进行网络分析以验证某些内容,则将看不到正确的输出,因为HTTP标头中使用的HTTP方法仍然POST不是您实际需要的。
–'code_dredd

8

不幸的是,现代浏览器不提供对HTTP PUT请求的本机支持。要变通解决此限制,请确保您的HTML表单的method属性为“ post”,然后将方法覆盖参数添加到您的HTML表单中,如下所示:

<input type="hidden" name="_METHOD" value="PUT"/>

要测试您的请求,您可以使用Google Chrome扩展程序“邮递员”


1
它应适用于任何方法,包括DELETE和PATCH等
Tofeeq

1

要设置方法PUT和DELETE,请执行以下操作:

<form
  method="PUT"
  action="domain/route/param?query=value"
>
  <input type="hidden" name="delete_id" value="1" />
  <input type="hidden" name="put_id" value="1" />
  <input type="text" name="put_name" value="content_or_not" />
  <div>
    <button name="update_data">Save changes</button>
    <button name="remove_data">Remove</button>
  </div>
</form>
<hr>
<form
  method="DELETE"
  action="domain/route/param?query=value"
>
  <input type="hidden" name="delete_id" value="1" />
  <input type="text" name="delete_name" value="content_or_not" />
  <button name="delete_data">Remove item</button>
</form>

然后,JS会执行所需的方法:

<script>
   var putMethod = ( event ) => {
     // Prevent redirection of Form Click
     event.preventDefault();
     var target = event.target;
     while ( target.tagName != "FORM" ) {
       target = target.parentElement;
     } // While the target is not te FORM tag, it looks for the parent element
     // The action attribute provides the request URL
     var url = target.getAttribute( "action" );

     // Collect Form Data by prefix "put_" on name attribute
     var bodyForm = target.querySelectorAll( "[name^=put_]");
     var body = {};
     bodyForm.forEach( element => {
       // I used split to separate prefix from worth name attribute
       var nameArray = element.getAttribute( "name" ).split( "_" );
       var name = nameArray[ nameArray.length - 1 ];
       if ( element.tagName != "TEXTAREA" ) {
         var value = element.getAttribute( "value" );
       } else {
       // if element is textarea, value attribute may return null or undefined
         var value = element.innerHTML;
       }
       // all elements with name="put_*" has value registered in body object
       body[ name ] = value;
     } );
     var xhr = new XMLHttpRequest();
     xhr.open( "PUT", url );
     xhr.setRequestHeader( "Content-Type", "application/json" );
     xhr.onload = () => {
       if ( xhr.status === 200 ) {
       // reload() uses cache, reload( true ) force no-cache. I reload the page to make "redirects normal effect" of HTML form when submit. You can manipulate DOM instead.
         location.reload( true );
       } else {
         console.log( xhr.status, xhr.responseText );
       }
     }
     xhr.send( body );
   }

   var deleteMethod = ( event ) => {
     event.preventDefault();
     var confirm = window.confirm( "Certeza em deletar este conteúdo?" );
     if ( confirm ) {
       var target = event.target;
       while ( target.tagName != "FORM" ) {
         target = target.parentElement;
       }
       var url = target.getAttribute( "action" );
       var xhr = new XMLHttpRequest();
       xhr.open( "DELETE", url );
       xhr.setRequestHeader( "Content-Type", "application/json" );
       xhr.onload = () => {
         if ( xhr.status === 200 ) {
           location.reload( true );
           console.log( xhr.responseText );
         } else {
           console.log( xhr.status, xhr.responseText );
         }
       }
       xhr.send();
     }
   }
</script>

定义了这些功能后,我将事件监听器添加到发出表单方法请求的按钮上:

<script>
  document.querySelectorAll( "[name=update_data], [name=delete_data]" ).forEach( element => {
    var button = element;
    var form = element;
    while ( form.tagName != "FORM" ) {
      form = form.parentElement;
    }
    var method = form.getAttribute( "method" );
    if ( method == "PUT" ) {
      button.addEventListener( "click", putMethod );
    }
    if ( method == "DELETE" ) {
      button.addEventListener( "click", deleteMethod );
    }
  } );
</script>

对于PUT表单上的删除按钮:

<script>
  document.querySelectorAll( "[name=remove_data]" ).forEach( element => {
    var button = element;
    button.addEventListener( "click", deleteMethod );
</script>

_------------

本文https://blog.garstasio.com/you-dont-need-jquery/ajax/对我有很大帮助!

除此之外,您可以根据需要设置postMethod函数和getMethod来处理POST和GET提交方法,而不是浏览器的默认行为。您可以执行任何您想使用的操作location.reload(),例如显示成功更改或成功删除的消息。

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

JSFiddle:https://jsfiddle.net/enriquerene/d6jvw52t/53/

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.