มันส่งไฟล์ภายในได้อย่างไร?
รูปแบบถูกเรียกmultipart/form-data
ตามที่ถามที่: enctype = 'multipart / form-data' หมายถึงอะไร
ผมกำลังจะไป:
- เพิ่มการอ้างอิง HTML5 เพิ่มเติม
- อธิบายว่าทำไมเขาถึงพูดถูกด้วยแบบฟอร์มส่งตัวอย่าง
การอ้างอิง HTML5
มีสามความเป็นไปได้สำหรับenctype
:
วิธีสร้างตัวอย่าง
เมื่อคุณเห็นตัวอย่างของแต่ละวิธีมันจะเห็นได้ชัดว่ามันทำงานอย่างไรและเมื่อคุณควรใช้แต่ละวิธี
คุณสามารถสร้างตัวอย่างโดยใช้:
บันทึกฟอร์มเป็น.html
ไฟล์ขั้นต่ำ:
<!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>
เราตั้งค่าข้อความเริ่มต้นเป็นaωb
ซึ่งหมายความว่าเป็นaωb
เพราะω
เป็นU+03C9
ไบต์61 CF 89 62
ใน UTF-8
สร้างไฟล์ที่จะอัพโหลด:
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
เรียกใช้เซิร์ฟเวอร์ echo เล็ก ๆ ของเรา:
while true; do printf '' | nc -l 8000 localhost; done
เปิด HTML บนเบราว์เซอร์ของคุณเลือกไฟล์และคลิกที่ส่งและตรวจสอบเทอร์มินัล
nc
พิมพ์คำขอที่ได้รับ
ทดสอบกับ: Ubuntu 14.04.3, nc
BSD 1.105, Firefox 40
multipart / form ข้อมูล
ส่ง Firefox แล้ว:
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--
สำหรับไฟล์ไบนารีและฟิลด์ข้อความไบต์61 CF 89 62
(เป็นaωb
UTF-8) จะถูกส่งไปตามตัวอักษร คุณสามารถตรวจสอบว่าด้วยnc -l localhost 8000 | hd
ซึ่งบอกว่าไบต์:
61 CF 89 62
ถูกส่งไป ( 61
== 'a' และ62
== 'b')
ดังนั้นจึงเป็นที่ชัดเจนว่า:
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
กำหนดประเภทเนื้อหาเป็นmultipart/form-data
และบอกว่าเขตข้อมูลจะถูกคั่นด้วยboundary
สตริงที่กำหนด
แต่ทราบว่า:
boundary=---------------------------735323031399963166993862150
มีสอง dadhes น้อย--
กว่าอุปสรรคที่เกิดขึ้นจริง
-----------------------------735323031399963166993862150
--
เพราะนี่คือมาตรฐานต้องมีขอบเขตที่จะเริ่มต้นด้วยการขีดสองขีด เครื่องหมายขีดคั่นอื่น ๆ ดูเหมือนจะเป็นเพียงวิธีที่ Firefox เลือกใช้ขอบเขตโดยพลการ RFC 7578 ระบุอย่างชัดเจนว่า--
จำเป็นต้องมีขีดกลางสองอันดังกล่าว:
4.1 "ขอบเขต" พารามิเตอร์ของหลายส่วน / แบบฟอร์มข้อมูล
เช่นเดียวกับชนิดหลายส่วนอื่น ๆ ชิ้นส่วนจะถูกคั่นด้วยตัวคั่นขอบเขตสร้างโดยใช้ CRLF, "-" และค่าของพารามิเตอร์ "ขอบเขต"
ทุกสาขาจะได้รับส่วนหัวย่อยบางอย่างก่อนที่ข้อมูลที่: Content-Disposition: form-data;
สนามname
ที่filename
ตามด้วยข้อมูล
เซิร์ฟเวอร์อ่านข้อมูลจนกว่าจะถึงขอบเขตของสตริงถัดไป เบราว์เซอร์จะต้องเลือกขอบเขตที่จะไม่ปรากฏในฟิลด์ใด ๆ ดังนั้นนี่คือสาเหตุที่ขอบเขตอาจแตกต่างกันระหว่างคำขอ
เนื่องจากเรามีขอบเขตที่ไม่ซ้ำกันจึงไม่จำเป็นต้องเข้ารหัสข้อมูล: ส่งข้อมูลไบนารีตามที่เป็นอยู่
สิ่งที่ต้องทำ: ขนาดขอบเขตที่เหมาะสมที่สุด ( log(N)
ฉันเดิมพัน) คืออะไรและชื่อ / เวลาทำงานของอัลกอริทึมที่พบมันคืออะไร ถามได้ที่: /cs/39687/find-the-shortest-sequence-that-is-not-a-s--ub-sequent-of-a-set-of-sequences
Content-Type
ถูกกำหนดโดยเบราว์เซอร์โดยอัตโนมัติ
มันถูกกำหนดอย่างไรถูกถามอย่างถูกต้องที่: ประเภทไฟล์ mime ที่อัพโหลดโดยเบราว์เซอร์เป็นอย่างไร?
แอพลิเคชัน / x-www ฟอร์ม urlencoded
ตอนนี้เปลี่ยนenctype
ไปapplication/x-www-form-urlencoded
โหลดเบราว์เซอร์และส่งอีกครั้ง
ส่ง Firefox แล้ว:
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
เห็นได้ชัดว่าข้อมูลไฟล์ไม่ได้ถูกส่ง แต่เป็นเพียงชื่อไฟล์ ดังนั้นจึงไม่สามารถใช้ไฟล์นี้ได้
สำหรับฟิลด์ข้อความเราจะเห็นว่าตัวอักษรที่พิมพ์ได้ปกติเหมือนa
และb
ถูกส่งไปในหนึ่งไบต์ในขณะที่ตัวอักษรที่ไม่สามารถพิมพ์ได้เช่นนั้น0xCF
และ0x89
เพิ่มขึ้น3 ไบต์แต่ละตัว: %CF%89
!
การเปรียบเทียบ
การอัปโหลดไฟล์มักจะมีอักขระที่ไม่สามารถพิมพ์ได้จำนวนมาก (เช่นรูปภาพ) ในขณะที่รูปแบบข้อความแทบจะไม่เคยทำเลย
จากตัวอย่างที่เราได้เห็นว่า:
multipart/form-data
: เพิ่มค่าใช้จ่ายขอบเขตจำนวนเล็กน้อยให้กับข้อความและต้องใช้เวลาในการคำนวณ แต่ส่งแต่ละไบต์เป็นหนึ่งไบต์
application/x-www-form-urlencoded
: มีขอบเขตไบต์เดียวต่อฟิลด์ ( &
) แต่เพิ่มค่าใช้จ่ายเชิงเส้นเป็น3xสำหรับอักขระที่ไม่สามารถพิมพ์ได้ทุกตัว
ดังนั้นแม้ว่าเราจะสามารถส่งไฟล์ได้application/x-www-form-urlencoded
เราก็ไม่ต้องการเพราะมันไม่มีประสิทธิภาพ
แต่สำหรับตัวอักษรที่พิมพ์ได้ที่พบในช่องข้อความมันไม่สำคัญและสร้างค่าใช้จ่ายน้อยลงดังนั้นเราจึงใช้มัน