Wykorzystanie metody PUT w formie HTML

175

Czy mogę użyć metody PUT w formularzu HTML, aby wysłać dane z formularza na serwer?

MyTitle
źródło

Odpowiedzi:

128

Formularze XHTML 1.x obsługują tylko GET i POST. GET i POST to jedyne dozwolone wartości atrybutu „metoda”.

dqhendricks
źródło
5
XHTML jest nieco przestarzały. Wciąż wygląda na to, że te same dwie wartości są prawidłowe w html5 developer.mozilla.org/en-US/docs/Web/HTML/Element/ ...
jakubiszon
194

Według standardu HTML , można nie . Jedyne poprawne wartości atrybutu metody to geti post, odpowiadające metodom GET i POST HTTP. <form method="put">jest nieprawidłowym kodem HTML i będzie traktowane jak <form>, tj. wyśle ​​żądanie GET.

Zamiast tego wiele frameworków po prostu używa parametru POST do tunelowania metody HTTP:

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

Oczywiście wymaga to rozpakowania po stronie serwera.

phihag
źródło
3
Łączyłeś wersję roboczą, a nie ostateczny standard. Uwaga, stabilne wersje HTML też tego nie oferują.
hakre
13
@hakre HTML5 jest już de facto standardem i prawdopodobnie z czasem będzie ewoluował. To, co W3C nazywa „wersją roboczą”, jest udokumentowanym opracowaniem przez co najmniej 3 lata przy udziale producentów przeglądarek z ponad 99% i zostało już wdrożone (przynajmniej jeśli chodzi o tę i większość nie-ezoterycznych sekcji) przez wszystkie na zawsze. Ale tylko dla szperaczy, oto równoważna definicja w HTML 4.01 (Żądanie techniczne w terminach W3C).
phihag
Proszę nie czuć się urażonym, już napisałem, że to tylko uwaga i że inne wersje HTML też jej nie oferują (z niewielkim wyjątkiem XHTML 2, ale jest to już przestarzała wersja robocza).
hakre
1
@hakre Zapewniamy, że wcale mnie nie obrażam. Nitpicking the nitpicker, muszę skomentować, że XHTML nie jest technicznie HTML, chociaż można znaleźć jedno lub dwa podobieństwa;)
phihag
44

Czy mogę użyć metody „Put” w formularzu html do wysyłania danych z formularza HTML na serwer?

Tak, możesz, ale pamiętaj, że nie spowoduje to PUT, ale żądanie GET. Jeśli użyjesz nieprawidłowej wartości methodatrybutu <form>tagu, przeglądarka użyje wartości domyślnej get.

Formularze HTML (do wersji HTML 4 (, 5 Draft) i XHTML 1) obsługują tylko metody GET i POST jako metody żądania HTTP. Obejściem tego problemu jest tunelowanie innych metod przez POST przy użyciu ukrytego pola formularza, które jest odczytywane przez serwer i odpowiednio wysyłane żądanie. XHTML 2.0 planował kiedyś wspierać GET, POST, PUT i DELETE dla formularzy, ale przechodzi do XHTML5 w HTML5 , który nie planuje obsługiwać PUT. [Uaktualnij do]

Alternatywnie możesz zaoferować formularz, ale zamiast go przesyłać, utwórz i uruchom XMLHttpRequest przy użyciu metody PUT z JavaScript.

hakre
źródło
Żądanie AJAX nie może całkowicie zastąpić żądania formularza, ponieważ żądanie formularza przekierowuje użytkownika do podanego zasobu. Na przykład w tej chwili nie ma możliwości wyświetlenia w przeglądarce strony trasy PUT /resource.
JacopoStanchi,
To zły pomysł. Struktury mogą ignorować parametry formularza dla PUT. Wydaje się, że serwlet HTTPS Javy tak. Wystąpił błąd polegający na tym, HttpRequest.getParameterMap()że nie zwracano parametrów formularza.
DaBlick,
@DaBlick: Ale nie dla XMLHttpRequests? Jeśli tak, to poleganie na interfejsie API pobierania powinno być bardziej ustandaryzowane.
hakre
27

_method obejście ukrytego pola

Następująca prosta technika jest używana przez kilka frameworków internetowych:

  • dodaj ukryty _methodparametr do dowolnego formularza, który nie jest GET ani POST:

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

    Można to zrobić automatycznie w frameworkach za pomocą metody pomocnika tworzenia HTML.

  • napraw rzeczywistą metodę formularza na POST ( <form method="post")

  • procesy _methodna serwerze i robią dokładnie tak, jakby ta metoda została wysłana zamiast faktycznego POST

Możesz to osiągnąć w:

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

Uzasadnienie / historia, dlaczego nie jest to możliwe w czystym HTML: /software/114156/why-there-are-no-put-and-delete-methods-in-html-forms

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
źródło
Laravel (php) ma tę samą funkcję, używając@method("PATCH")
santiago arizti
Wydaje się, że jest to rozsądne obejście, ale nadal niefortunne, ponieważ utrudnia debugowanie. Na przykład, jeśli musisz przejrzeć dzienniki serwera lub przeprowadzić analizę sieci, aby zweryfikować niektóre rzeczy, nie zobaczysz poprawnych danych wyjściowych, ponieważ metoda HTTP używana w nagłówkach HTTP nadal jest POSTtym, czego faktycznie potrzebujesz.
code_dredd
8

Niestety, nowoczesne przeglądarki nie zapewniają natywnej obsługi żądań HTTP PUT. Aby obejść to ograniczenie, upewnij się, że atrybut metody formularza HTML to „post”, a następnie dodaj parametr przesłaniający metodę do formularza HTML w następujący sposób:

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

Aby przetestować swoje żądania, możesz użyć rozszerzenia Google Chrome „Postman”

Tofeeq
źródło
1
Powinien działać dla każdej metody, w tym DELETE AND PATCH itp.
Tofeeq
1

Aby ustawić metody PUT i DELETE, wykonuję następujące czynności:

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

Następnie JS działa, aby wykonać żądane metody:

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

Po zdefiniowaniu tych funkcji dodaję detektor zdarzeń do przycisków, które powodują żądanie metody formularza:

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

A dla przycisku usuwania w formularzu PUT:

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

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

Ten artykuł https://blog.garstasio.com/you-dont-need-jquery/ajax/ bardzo mi pomaga!

Poza tym możesz ustawić funkcję postMethod i getMethod do obsługi metod przesyłania POST i GET w dowolny sposób, zamiast domyślnego zachowania przeglądarki. Zamiast tego możesz zrobić, co chcesz location.reload(), na przykład pokazać komunikat o udanych zmianach lub pomyślnym usunięciu.

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

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

Enrique René
źródło