Bagaimana cara mengirim file secara internal?
Format ini disebut multipart/form-data
, seperti yang ditanyakan pada: Apa arti enctype = 'multipart / form-data'?
Saya akan:
- tambahkan beberapa referensi HTML5 lainnya
- jelaskan mengapa dia benar dengan formulir serahkan contoh
Referensi HTML5
Ada tiga kemungkinan untuk enctype
:
Cara menghasilkan contoh
Setelah Anda melihat contoh masing-masing metode, menjadi jelas bagaimana cara kerjanya, dan kapan Anda harus menggunakannya.
Anda dapat menghasilkan contoh menggunakan:
Simpan formulir ke .html
file minimal :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>upload</title>
</head>
<body>
<form action="http://localhost:8000" method="post" enctype="multipart/form-data">
<p><input type="text" name="text1" value="text default">
<p><input type="text" name="text2" value="aωb">
<p><input type="file" name="file1">
<p><input type="file" name="file2">
<p><input type="file" name="file3">
<p><button type="submit">Submit</button>
</form>
</body>
</html>
Kami menetapkan nilai teks default menjadi aωb
, yang berarti aωb
karena ω
is U+03C9
, yang merupakan byte61 CF 89 62
dalam UTF-8.
Buat file untuk diunggah:
echo 'Content of a.txt.' > a.txt
echo '<!DOCTYPE html><title>Content of a.html.</title>' > a.html
# Binary file containing 4 bytes: 'a', 1, 2 and 'b'.
printf 'a\xCF\x89b' > binary
Jalankan server gema kecil kami:
while true; do printf '' | nc -l 8000 localhost; done
Buka HTML di browser Anda, pilih file dan klik kirim dan periksa terminal.
nc
mencetak permintaan yang diterima.
Diuji pada: Ubuntu 14.04.3, nc
BSD 1.105, Firefox 40.
multipart / formulir-data
Firefox mengirim:
POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
Content-Length: 834
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text1"
text default
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="text2"
aωb
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain
Content of a.txt.
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html
<!DOCTYPE html><title>Content of a.html.</title>
-----------------------------735323031399963166993862150
Content-Disposition: form-data; name="file3"; filename="binary"
Content-Type: application/octet-stream
aωb
-----------------------------735323031399963166993862150--
Untuk file biner dan bidang teks, byte 61 CF 89 62
( aωb
dalam UTF-8) dikirim secara harfiah. Anda dapat memverifikasi itu dengan nc -l localhost 8000 | hd
, yang mengatakan bahwa byte:
61 CF 89 62
dikirim ( 61
== 'a' dan 62
== 'b').
Karena itu jelas bahwa:
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
setel jenis konten menjadi multipart/form-data
dan mengatakan bahwa bidang dipisahkan oleh boundary
string yang diberikan .
Tetapi perhatikan bahwa:
boundary=---------------------------735323031399963166993862150
memiliki dua ayah kurang --
dari penghalang yang sebenarnya
-----------------------------735323031399963166993862150
Ini karena standar mengharuskan batas untuk memulai dengan dua tanda hubung --
. Tanda hubung lainnya tampaknya hanya bagaimana Firefox memilih untuk menerapkan batas arbitrer. RFC 7578 dengan jelas menyebutkan bahwa kedua tanda hubung utama --
diperlukan:
4.1. "Batas" Parameter multipart / formulir-data
Seperti jenis multi bagian lainnya, bagian-bagian dibatasi dengan pembatas batas, dibangun menggunakan CRLF, "-", dan nilai parameter "batas".
setiap bidang mendapatkan beberapa subjudul sebelum datanya Content-Disposition: form-data;
:, bidang name
,filename
, diikuti oleh data.
Server membaca data hingga string batas berikutnya. Peramban harus memilih batas yang tidak akan muncul di bidang mana pun, jadi inilah sebabnya batas mungkin berbeda di antara permintaan.
Karena kami memiliki batas unik, tidak diperlukan penyandian data: data biner dikirim apa adanya.
TODO: berapakah ukuran batas optimal ( log(N)
saya yakin), dan nama / waktu berjalan dari algoritma yang menemukannya? Ditanya di: /cs/39687/find-the-shortest- berikutnyaence-that-is-not-a-sub- berikutnyaence- of-a- set- of- afterences
Content-Type
ditentukan secara otomatis oleh browser.
Bagaimana ditentukan dengan tepat ditanyakan di: Bagaimana jenis mime dari file yang diunggah ditentukan oleh browser?
application / x-www-form-urlencoded
Sekarang ubah enctype
ke application/x-www-form-urlencoded
, muat ulang peramban, dan kirim kembali.
Firefox mengirim:
POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: application/x-www-form-urlencoded
Content-Length: 51
text1=text+default&text2=a%CF%89b&file1=a.txt&file2=a.html&file3=binary
Jelas data file tidak dikirim, hanya nama dasarnya. Jadi ini tidak dapat digunakan untuk file.
Sedangkan untuk bidang teks, kita melihat bahwa karakter yang biasa dicetak suka a
dan b
dikirim dalam satu byte, sementara yang tidak dapat dicetak suka 0xCF
dan masing-masing 0x89
mengambil 3 byte :%CF%89
!
Perbandingan
Unggahan file sering mengandung banyak karakter yang tidak dapat dicetak (mis. Gambar), sedangkan bentuk teks hampir tidak pernah dilakukan.
Dari contoh-contoh yang telah kita lihat bahwa:
multipart/form-data
: menambahkan beberapa byte batas overhead ke pesan, dan harus meluangkan waktu untuk menghitungnya, tetapi mengirimkan setiap byte dalam satu byte.
application/x-www-form-urlencoded
: memiliki batas byte tunggal per bidang ( &
), tetapi menambahkan faktor overhead linier 3x untuk setiap karakter yang tidak dapat dicetak.
Karena itu, bahkan jika kita dapat mengirim file application/x-www-form-urlencoded
, kami tidak akan mau, karena sangat tidak efisien.
Tetapi untuk karakter yang dapat dicetak ditemukan di bidang teks, itu tidak masalah dan menghasilkan lebih sedikit overhead, jadi kami hanya menggunakannya.