Bagaimana parameter dikirim dalam permintaan HTTP POST?

1476

Dalam permintaan GET HTTP , parameter dikirim sebagai string kueri :

http://example.com/page ? parameter = value & juga = yang lain

Dalam permintaan HTTP POST , parameter tidak dikirim bersama dengan URI.

Di mana nilainya? Di header permintaan? Di badan permintaan? Seperti apa bentuknya?

Camilo Martin
sumber

Jawaban:

1254

Nilai dikirim dalam tubuh permintaan, dalam format yang ditentukan oleh tipe konten.

Biasanya tipe kontennya application/x-www-form-urlencoded, jadi badan permintaan menggunakan format yang sama dengan string kueri:

parameter=value&also=another

Saat Anda menggunakan unggahan file dalam formulir, Anda menggunakan multipart/form-datapenyandian yang memiliki format berbeda. Ini lebih rumit, tetapi Anda biasanya tidak perlu peduli seperti apa itu, jadi saya tidak akan menunjukkan contoh, tetapi mungkin baik untuk mengetahui bahwa itu ada.

Guffa
sumber
25
Saya lupa tentang unggahan file yang berbeda (+ 1 / diterima). Jawaban Anda cukup, sementara itu akan lebih baik jika memiliki lebih banyak info multipart/form-data. Bagi mereka yang tertarik, inilah pertanyaan tentang itu .
Camilo Martin
73
CATATAN : badan dipisahkan dari header dengan hanya satu baris kosong .
Gab 是 好人
2
Anda menjelaskan apa yang kami tempatkan di HTTPBody, tetapi apa yang kami tempatkan / tulis di HTTPHeader? Apa tujuannya?
Sayang
4
@ Madu: Header HTTP untuk sebuah posting terlihat seperti satu untuk mendapatkan, tetapi dengan kata kerja POST bukannya GET, dan nilai jenis konten (dan nilai panjang konten opsional) karena permintaan memiliki konten (tubuh). Setiap jenis permintaan memiliki tajuk, beberapa jenis juga memiliki badan.
Guffa
4
@KennethWorden Tidak, selain metode akan mengirim JSON dengan benar. Namun Anda dapat mengunggah file json dalam bentuk yang dikodekan dengan multipart/form-dataatau jika Anda bertanggung jawab atas permintaan konstruksi, ubah tipe konten ke application/jsondan tempel teks json di tubuh http secara langsung
Cholthi Paul Ttiopic
428

Konten diletakkan setelah header HTTP. Format HTTP POST adalah memiliki tajuk HTTP, diikuti oleh baris kosong, diikuti oleh badan permintaan. Variabel POST disimpan sebagai pasangan kunci-nilai dalam tubuh.

Anda dapat melihat ini di konten mentah dari HTTP Post, ditunjukkan di bawah:

POST /path/script.cgi HTTP/1.0
From: [email protected]
User-Agent: HTTPTool/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 32

home=Cosby&favorite+flavor=flies

Anda dapat melihat ini menggunakan alat seperti Fiddler , yang dapat Anda gunakan untuk menonton permintaan HTTP mentah dan muatan respons yang dikirim melintasi kawat.

Joe Alfano
sumber
39
Hanya jika jenis kontennya application/x-www-form-urlencoded, yang tidak selalu terjadi.
Guffa
@ Camilo Martin .... [+1] untuk pertanyaan hebat & @ Joe Alfano .... [+1] untuk jawaban yang bagus ....... sekarang saya punya ide yang jelas tentang permintaan POST .... tetapi jika sebuah gambar datang bersama kunci, nilai pasangan informasi data ..... Bagaimana struktur POST terlihat?
Devrath
9
@ Jo, Sekarang mengapa Anda memiliki Fromheader di sana?
Pacerier
@ Jo, saya suka dimasukkannya Fromheader secara acak . IMO ada di atas sana dengan kode status HTTP 418.
Tom Howard
bagaimana Anda menambahkan otentikasi pengguna dan kata sandi?
m4l490n
376

Jawaban singkat: dalam permintaan POST, nilai dikirim dalam "badan" permintaan. Dengan formulir web, mereka kemungkinan besar dikirim dengan jenis media application/x-www-form-urlencodedatau multipart/form-data. Bahasa pemrograman atau kerangka kerja yang telah dirancang untuk menangani permintaan web biasanya melakukan "The Right Thing ™" dengan permintaan seperti itu dan memberi Anda akses mudah ke nilai yang siap diterjemahkan (seperti $_REQUESTatau $_POSTdalam PHP, atau cgi.FieldStorage(), flask.request.formdengan Python).


Sekarang mari kita sedikit ngelantur, yang mungkin bisa membantu memahami perbedaannya;)

Perbedaan antara GETdan POSTpermintaan sebagian besar bersifat semantik. Mereka juga "digunakan" secara berbeda, yang menjelaskan perbedaan dalam bagaimana nilai-nilai dilewatkan.

DAPATKAN ( bagian RFC yang relevan )

Saat menjalankan GETpermintaan, Anda meminta satu atau beberapa entitas pada server. Untuk memungkinkan klien memfilter hasilnya, ia dapat menggunakan apa yang disebut "string kueri" dari URL. String kueri adalah bagian setelah ?. Ini adalah bagian dari sintaks URI .

Jadi, dari sudut pandang kode aplikasi Anda (bagian yang menerima permintaan), Anda perlu memeriksa bagian permintaan URI untuk mendapatkan akses ke nilai-nilai ini.

Perhatikan bahwa kunci dan nilai adalah bagian dari URI. Browser dapat menetapkan batas panjang URI. Standar HTTP menyatakan bahwa tidak ada batasan. Tetapi pada saat penulisan ini, kebanyakan browser jangan membatasi URI (saya tidak memiliki nilai-nilai tertentu). GETpermintaan tidak boleh digunakan untuk mengirimkan informasi baru ke server. Terutama bukan dokumen yang lebih besar. Di situlah Anda harus menggunakan POSTatau PUT.

POST ( bagian RFC yang relevan )

Saat menjalankan POSTpermintaan, klien sebenarnya mengirimkan dokumen baru ke host jarak jauh. Jadi, string kueri tidak (secara semantik) masuk akal. Itulah sebabnya Anda tidak memiliki akses ke mereka dalam kode aplikasi Anda.

POSTsedikit lebih kompleks (dan jauh lebih fleksibel):

Saat menerima permintaan POST, Anda harus selalu mengharapkan "muatan", atau, dalam istilah HTTP: badan pesan . Isi pesan itu sendiri sangat tidak berguna, karena tidak ada format standar (sejauh yang saya tahu. Mungkin aplikasi / octet-stream?). Format tubuh ditentukan oleh Content-Typetajuk. Saat menggunakan FORMelemen HTML dengan method="POST", ini biasanya application/x-www-form-urlencoded. Jenis lain yang sangat umum adalah multipart / formulir-data jika Anda menggunakan unggahan file. Tapi itu bisa apa saja , mulai dari text/plain, lebih, application/jsonatau bahkan kebiasaan application/octet-stream.

Dalam kasus apa pun, jika suatu POSTpermintaan dibuat dengan sesuatu Content-Typeyang tidak dapat ditangani oleh aplikasi, itu harus mengembalikan 415kode status .

Sebagian besar bahasa pemrograman (dan / atau kerangka kerja web) menawarkan cara untuk menghapus / menyandikan isi pesan dari / ke jenis yang paling umum (seperti application/x-www-form-urlencoded, multipart/form-dataatau application/json). Jadi itu mudah. Jenis kustom memerlukan pekerjaan yang berpotensi sedikit lebih banyak.

Menggunakan dokumen penyandian formulir HTML standar sebagai contoh, aplikasi harus melakukan langkah-langkah berikut:

  1. Baca Content-Typebidangnya
  2. Jika nilainya bukan jenis media yang didukung, maka kembalikan respons dengan 415kode status
  3. jika tidak, dekode nilai dari badan pesan.

Sekali lagi, bahasa seperti PHP, atau kerangka kerja web untuk bahasa populer lainnya mungkin akan menangani ini untuk Anda. Pengecualian untuk ini adalah 415kesalahan. Tidak ada kerangka kerja yang dapat memprediksi jenis konten mana yang dipilih aplikasi Anda untuk mendukung dan / atau tidak mendukung. Ini terserah kamu.

PUT ( bagian RFC yang relevan )

Sebuah PUTpermintaan cukup banyak ditangani dengan cara yang sama persis sebagai POSTpermintaan. Perbedaan besar adalah bahwa POSTpermintaan seharusnya membiarkan server memutuskan bagaimana (dan jika sama sekali) membuat sumber daya baru. Secara historis (dari RFC2616 yang sekarang sudah usang itu adalah untuk menciptakan sumber daya baru sebagai "bawahan" (anak) dari URI di mana permintaan dikirim ke).

Sebuah PUTpermintaan kontras seharusnya "deposit" sumber daya tepatnya di URI, dan dengan tepat konten tersebut. Tidak lebih, tidak kurang. Idenya adalah bahwa klien bertanggung jawab untuk menyusun sumber daya yang lengkap sebelum "PUTting" itu. Server harus menerimanya apa adanya di URL yang diberikan.

Akibatnya, POSTpermintaan biasanya tidak digunakan untuk mengganti sumber daya yang ada. Sebuah PUTpermintaan dapat melakukan keduanya membuat dan mengganti.

Catatan Samping

Ada juga " parameter path " yang dapat digunakan untuk mengirim data tambahan ke remote, tetapi mereka sangat jarang, sehingga saya tidak akan membahas terlalu banyak detail di sini. Tapi, untuk referensi, berikut adalah kutipan dari RFC:

Selain dari segmen-segmen dalam jalur hierarkis, segmen jalur dianggap buram oleh sintaksis generik. Aplikasi penghasil URI sering menggunakan karakter-karakter khusus yang diperbolehkan dalam segmen untuk membatasi subkomponen khusus skema atau spesifik-handler. Misalnya, tanda titik koma (";") dan sama dengan ("=") karakter cadangan sering digunakan untuk membatasi parameter dan nilai parameter yang berlaku untuk segmen itu. Karakter khusus koma (",") sering digunakan untuk tujuan yang sama. Misalnya, satu produsen URI mungkin menggunakan segmen seperti "nama; v = 1.1" untuk menunjukkan referensi ke versi 1.1 dari "nama", sedangkan yang lain mungkin menggunakan segmen seperti "nama, 1.1" untuk menunjukkan hal yang sama. Jenis parameter dapat ditentukan oleh semantik khusus skema,

exhuma
sumber
1
Aku mungkin memang agak bersinggungan. Saya menambahkan "tl; dr" ke bagian atas jawaban yang seharusnya membuatnya lebih jelas.
exhuma
Saya juga baru saja mengeditnya untuk referensi RFC7231 bukan RFC2616 (yang telah usang untuk sementara waktu). Perbedaan utama untuk jawaban ini selain dari tautan yang diperbarui, ada di bagian "PUT".
exhuma
Saya pikir PUT ditangani secara berbeda dari POST karena seharusnya idempoten? stackoverflow.com/questions/611906/…
rogerdpack
1
@rogerdpack Anda tidak salah. Jika Anda membaca paragraf kedua di PUTbagian, Anda akan melihat bahwa itu adalah idempoten. POSTsebaliknya bisa - menurut definisi - tidak bisa. POSTakan selalu membuat sumber daya baru. PUTakan, jika ada sumber daya identik menggantinya. Jadi, jika Anda menelepon POST10 kali, Anda akan membuat 10 sumber daya. Jika Anda menelepon PUT10 kali, itu akan (mungkin) hanya membuat satu. Apakah itu menjawab pertanyaan Anda?
exhuma
60

Anda tidak dapat mengetik secara langsung di bilah URL peramban.

Anda dapat melihat bagaimana data POST dikirim di Internet dengan Header HTTP Langsung misalnya. Hasilnya akan seperti itu

http://127.0.0.1/pass.php
POST /pass.php HTTP/1.1

Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://127.0.0.1/pass.php
Cookie: passx=87e8af376bc9d9bfec2c7c0193e6af70; PHPSESSID=l9hk7mfh0ppqecg8gialak6gt5
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 30
username=zurfyx&pass=password

Dimana katanya

Content-Length: 30
    username=zurfyx&pass=password

akan menjadi nilai posting.

zurfyx
sumber
2
Klarifikasi: apakah Content-Lengthseharusnya ada di 29sini? Itulah panjang tali yang sebenarnya username=zurfyx&pass=password.
Hippo
@Hippo adalah karakter baris baru yang seharusnya ada di sana?
vikingsteve
@vikingsteve, aku mengerti maksudmu. Jadi saya kira Konten selalu memiliki baris baru di akhir, lalu.
Hippo
2
Header dipisahkan dari badan dengan baris baru ekstra
Mára Toner
24

Jenis media standar dalam permintaan POST adalah application/x-www-form-urlencoded. Ini adalah format untuk penyandian pasangan nilai kunci. Kunci dapat digandakan. Setiap pasangan nilai kunci dipisahkan oleh &karakter, dan setiap kunci dipisahkan dari nilainya oleh =karakter.

Sebagai contoh:

Name: John Smith
Grade: 19

Dikodekan sebagai:

Name=John+Smith&Grade=19

Ini ditempatkan di badan permintaan setelah tajuk HTTP.

Nejat
sumber
1
Anda menjelaskan apa yang kami tempatkan di HTTPBody, tetapi apa yang kami tempatkan / tulis di HTTPHeader?
Sayang
Anda menyebutkan bahwa kuncinya dapat digandakan, lalu apa hasil dari duplikat seperti itu? Apakah yang terakhir akan secara otomatis menimpa nilai sebelumnya? Terima kasih.
Jinghui Niu
@ JinghuiNiu jika kuncinya adalah duplikat itu harus diuraikan sebagai array. Ini sangat terlambat tetapi mungkin bisa membantu orang lain.
Hanash Yaslem
18

Nilai formulir dalam HTTP POST dikirim dalam tubuh permintaan, dalam format yang sama dengan querystring.

Untuk informasi lebih lanjut, lihat spesifikasi .

Slaks
sumber
5
"Format yang sama" agak ambigu. Apakah mereka mulai dengan ?contoh?
Camilo Martin
7
@PeterWooster Ya, tetapi tidak memberikan contoh. Dalam hal itu, seperti jawaban yang mengatakan "lihat, ada jawaban untuk pertanyaan Anda di blog aplikasi (tautan) ".
Camilo Martin
36
@PeterWooster Tidak diperlukan, tetapi sangat baik ketika Anda melupakan sesuatu, google saja, buka tautan pertama yang SO, dan ada contoh yang jelas dan ringkas yang memberi tahu Anda apa yang Anda butuhkan daripada mengirim Anda untuk mengunyah spesifikasi yang terlalu rinci yang, bahkan jika komprehensif, mungkin tidak cocok untuk penyegar. Pikirkan tentang hal ini: sebagian besar QA di situs ini dapat menjadi "baca spesifikasi / manual / API / etc (tautan) ". Apakah ini berguna? Tidak lebih dari Google.
Camilo Martin
2
Hanya jika jenis kontennya application/x-www-form-urlencoded, yang tidak selalu terjadi.
Guffa
3
Format string kueri GET berbeda dari urlencode aplikasi / x-www-form. Misalnya, spasi putih dikodekan secara berbeda (% 20 vs +). Jawabannya menyesatkan dalam hal ini.
UnclickableCharacter
18

Beberapa layanan web mengharuskan Anda untuk menempatkan data permintaan dan metadata secara terpisah. Misalnya fungsi jarak jauh mungkin berharap bahwa string metadata yang ditandatangani termasuk dalam URI, sementara data diposting di badan HTTP.

Permintaan POST mungkin secara semantik terlihat seperti ini:

POST /?AuthId=YOURKEY&Action=WebServiceAction&Signature=rcLXfkPldrYm04 HTTP/1.1
Content-Type: text/tab-separated-values; charset=iso-8859-1
Content-Length: []
Host: webservices.domain.com
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: identity
User-Agent: Mozilla/3.0 (compatible; Indy Library)

name    id
John    G12N
Sarah   J87M
Bob     N33Y

Pendekatan ini secara logis menggabungkan QueryString dan Body-Post menggunakan satu Content-Typeyang merupakan "parsing-instructions" untuk server web.

Harap dicatat: HTTP / 1.1 dibungkus dengan #32(spasi) di sebelah kiri dan dengan #10(Umpan baris) di sebelah kanan.

Antarmuka Tidak Diketahui
sumber
Perbedaan antara /user/johndan /?user=johnhanya semantik (HTTP tidak benar-benar memberikan perlakuan khusus untuk string kueri), jadi saya menganggap ini sesuai yang diharapkan. Tapi apa yang Anda maksud dengan "dibungkus oleh ruang di sebelah kiri"? Tidak ada spasi sebelum metode HTTP. Maksud Anda baris kosong untuk badan pos?
Camilo Martin
Ada spasi (ASCII # 32) antara ...Ym04dan HTTP/1.1dalam kode di atas. Jadi QueryString hanya tinggal di antara kata kerja dan versi protokol.
Antarmuka Tidak Diketahui
1
Catatan Anda membuatnya terdengar seperti sesuatu yang tidak terduga dan khusus versi. Sejujurnya sepertinya jelas ada ruang di sana. Dan feed baris juga berlaku untuk baris lain, seperti semua hal unix.
Camilo Martin
1
Saya hanya menekankan apa yang saya tidak bisa tandai dalam kode. Ini mungkin tampak jelas tetapi kadang-kadang tidak.
Antarmuka Tidak Diketahui
Memang benar bahwa kami dapat meneruskan parameter kueri sebagai bagian dari URL dengan memisahkan URI dan parameter dengan ?seperti yang kami lakukan dengan GETpermintaan.
asgs
8

Pertama-tama, mari kita bedakan antara GETdanPOST

Dapatkan: Ini adalah HTTPpermintaan default yang dibuat ke server dan digunakan untuk mengambil data dari server dan string kueri yang muncul setelah ?dalam URIdigunakan untuk mengambil sumber daya yang unik.

ini formatnya

GET /someweb.asp?data=value HTTP/1.0

di sini data=valueadalah nilai string kueri yang diteruskan.

POST: Digunakan untuk mengirim data ke server dengan aman sehingga apa pun yang diperlukan, ini adalah format POSTpermintaan

POST /somweb.aspHTTP/1.0
Host: localhost
Content-Type: application/x-www-form-urlencoded //you can put any format here
Content-Length: 11 //it depends
Name= somename

Mengapa POST over GET?

Dalam GETnilai yang dikirim ke server biasanya ditambahkan ke URL dasar dalam string kueri, sekarang ada 2 konsekuensi dari ini

  • The GETpermintaan yang disimpan dalam sejarah browser dengan parameter. Jadi kata sandi Anda tetap tidak terenkripsi dalam riwayat browser. Ini adalah masalah nyata bagi Facebook saat itu.
  • Biasanya server memiliki batasan berapa lama URI. Jika memiliki terlalu banyak parameter yang dikirim, Anda mungkin menerima414 Error - URI too long

Dalam hal permintaan posting, data Anda dari bidang ditambahkan ke badan sebagai gantinya. Panjang params permintaan dihitung, dan ditambahkan ke header untuk panjang konten dan tidak ada data penting yang ditambahkan langsung ke URL.

Anda dapat menggunakan bagian jaringan Alat Pengembang Google untuk melihat informasi dasar tentang bagaimana permintaan dibuat ke server.

dan Anda selalu dapat menambahkan nilai lebih di Anda Request Headersseperti Cache-Control, Origin, Accept.

Zeeshan Adil
sumber
4
Asumsi tentang keamanan hanya berlaku dalam konteks HTTPSkoneksi, tidak HTTP. HTTPSmengenkripsi baik URL(termasuk permintaan params) dan Request Body, ketika HTTPmengenkripsi / melindungi keduanya. Masalah yang dijelaskan berasal dari fakta bahwa banyak peramban menyimpan URIs(termasuk URLs) dalam basis data riwayat mereka (biasanya tidak dienkripsi). Jadi, gunakan hanya Request Body+ HTTPSuntuk apa pun yang sensitif.
Petru Zaharia
@PetruZaharia Saya setuju dengan penjelasan Anda. Anda juga dapat menyarankan ini sebagai edit dan saya akan dengan senang hati menerima! :)
Zeeshan Adil