Usando o método PUT no formulário HTML

175

Posso usar um método PUT em um formulário HTML para enviar dados do formulário para um servidor?

MyTitle
fonte

Respostas:

128

Os formulários XHTML 1.x suportam apenas GET e POST. GET e POST são os únicos valores permitidos para o atributo "method".

dqhendricks
fonte
5
XHTML está um pouco desatualizado. Ainda que parece mesmos dois valores são válidos em html5 developer.mozilla.org/en-US/docs/Web/HTML/Element/...
jakubiszon
194

De acordo com o padrão HTML , você não pode . Os únicos valores válidos para o atributo method são gete post, correspondendo aos métodos HTTP GET e POST. <form method="put">é HTML inválido e será tratado como <form>, por exemplo, envie uma solicitação GET.

Em vez disso, muitas estruturas simplesmente usam um parâmetro POST para encapsular o método HTTP:

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

Obviamente, isso requer desembrulhar do lado do servidor.

phihag
fonte
3
Você vinculou um rascunho, não um padrão final. Apenas observando, as versões HTML estáveis ​​também não oferecem.
hakre
13
@hakre HTML5 já é o padrão de fato e provavelmente evoluirá com o tempo. O que o W3C chama de "Rascunho" é um documento desenvolvido ao longo de pelo menos 3 anos, com a contribuição de fornecedores de navegadores com mais de> 99%, e já foi implementado (pelo menos no que diz respeito a esta e a maioria das seções não esotéricas) por todos eles para sempre. Mas apenas para os nitpickers, aqui está a definição equivalente no HTML 4.01 (uma solicitação técnica nos termos do W3C).
phihag
Por favor, não se sinta ofendido, eu já escrevi que é apenas uma observação e que as outras versões HTML também não a oferecem (com uma pequena exceção do XHTML 2, mas agora é um rascunho obsoleto).
hakre
1
@hakre Tenha certeza de que não estou ofendido. Picuinhas do nitpicker, devo comentar que XHTML não é tecnicamente HTML, embora se possa encontrar uma ou duas semelhanças;)
phihag
44

Posso usar o método "Put" no formulário html para enviar dados do formulário HTML para o servidor?

Sim, você pode, mas lembre-se de que isso não resultará em uma solicitação PUT, mas em uma solicitação GET. Se você usar um valor inválido para o methodatributo da <form>tag, o navegador usará o valor padrão get.

Os formulários HTML (até HTML versão 4 (, 5 rascunho) e XHTML 1) suportam apenas GET e POST como métodos de solicitação HTTP. Uma solução alternativa para isso é encapsular outros métodos através do POST usando um campo de formulário oculto que é lido pelo servidor e a solicitação enviada de acordo. O XHTML 2.0 planejou oferecer suporte a GET, POST, PUT e DELETE para formulários, mas está entrando no XHTML5 do HTML5 , que não planeja oferecer suporte ao PUT. [Atualizar para]

Como alternativa, você pode oferecer um formulário, mas, em vez de enviá-lo, crie e dispare um XMLHttpRequest usando o método PUT com JavaScript.

hakre
fonte
Uma solicitação AJAX não pode substituir completamente uma solicitação de formulário porque uma solicitação de formulário redireciona o usuário para o recurso especificado. Por exemplo, não há como, no momento, mostrar no navegador a página da rota PUT /resource.
JacopoStanchi
É uma má idéia fazer isso. Estruturas podem ignorar parâmetros de formulário para PUTs. O HTTPServlet do Java parece. Tivemos um erro em HttpRequest.getParameterMap()que não retornamos parâmetros de formulário.
DaBlick
@DaBlick: Mas não para XMLHttpRequests? Nesse caso, confiar na API de busca deve ser mais padronizado.
hakre
26

_method solução alternativa de campo oculto

A seguinte técnica simples é usada por algumas estruturas da web:

  • adicione um _methodparâmetro oculto a qualquer formulário que não seja GET ou POST:

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

    Isso pode ser feito automaticamente em estruturas através do método auxiliar de criação de HTML.

  • corrija o método de formulário real para POST ( <form method="post")

  • processos _methodno servidor e faça exatamente como se esse método tivesse sido enviado em vez do POST real

Você pode conseguir isso em:

  • Trilhos: form_tag
  • Laravel: @method("PATCH")

Justificativa / histórico do motivo pelo qual não é possível em HTML puro: /software/114156/why-there-are-no-put-and-delete-methods-in-html-forms

Ciro Santilli adicionou uma nova foto
fonte
Laravel (php) tem a mesma função utilizando@method("PATCH")
santiago Arizti
Parece uma solução razoável, mas ainda lamentável, pois dificulta a depuração. Por exemplo, se você precisar passar pelos logs do servidor ou fazer uma análise de rede para verificar algumas coisas, não verá a saída correta, pois o método HTTP usado nos cabeçalhos HTTP ainda é POSTe não é o que você realmente precisava.
code_dredd
8

Infelizmente, os navegadores modernos não fornecem suporte nativo para solicitações HTTP PUT. Para contornar essa limitação, verifique se o atributo do método do seu formulário HTML é "post" e adicione um parâmetro de substituição de método ao seu formulário HTML como este:

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

Para testar seus pedidos, você pode usar "Postman" uma extensão do google chrome

Tofeeq
fonte
1
Ele deve funcionar para qualquer método incluindo apagar e PATCH etc
Tofeeq
1

Para definir os métodos PUT e DELETE, execute o seguinte:

<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>

Em seguida, o JS atua para executar os métodos desejados:

<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>

Com essas funções definidas, adiciono um ouvinte de evento aos botões que solicitam o método do formulário:

<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>

E para o botão remover no formulário PUT:

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

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

Este artigo https://blog.garstasio.com/you-dont-need-jquery/ajax/ me ajuda muito!

Além disso, você pode definir a função postMethod e getMethod para manipular os métodos de envio POST e GET conforme desejar, em vez do comportamento padrão do navegador. Você pode fazer o que quiser location.reload(), como mostrar a mensagem de alterações bem-sucedidas ou exclusão bem-sucedida.

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

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

Enrique René
fonte