Câu trả lời:
Khi bạn thực hiện một yêu cầu POST, bạn phải mã hóa dữ liệu tạo thành phần thân của yêu cầu theo một cách nào đó.
Các hình thức HTML cung cấp ba phương pháp mã hóa.
application/x-www-form-urlencoded
(mặc định)multipart/form-data
text/plain
Công việc đã được thực hiện trên thêm application/json
, nhưng điều đó đã bị bỏ rơi.
(Các mã hóa khác có thể có với các yêu cầu HTTP được tạo bằng các phương tiện khác ngoài việc gửi biểu mẫu HTML. JSON là định dạng phổ biến để sử dụng với các dịch vụ web và một số vẫn sử dụng SOAP.)
Các chi tiết cụ thể của các định dạng không quan trọng đối với hầu hết các nhà phát triển. Những điểm quan trọng là:
text/plain
.Khi bạn đang viết mã phía máy khách:
multipart/form-data
khi biểu mẫu của bạn bao gồm bất kỳ <input type="file">
yếu tố nàomultipart/form-data
hay application/x-www-form-urlencoded
nhưng application/x-www-form-urlencoded
sẽ hiệu quả hơnKhi bạn đang viết mã phía máy chủ:
Hầu hết (chẳng hạn như Perl's CGI->param
hoặc người được tiếp xúc bởi siêu lớp của PHP $_POST
) sẽ quan tâm đến sự khác biệt dành cho bạn. Đừng cố gắng phân tích cú pháp đầu vào thô mà máy chủ nhận được.
Đôi khi bạn sẽ tìm thấy một thư viện không thể xử lý cả hai định dạng. Thư viện phổ biến nhất của Node.js để xử lý dữ liệu biểu mẫu là trình phân tích cú pháp cơ thể không thể xử lý các yêu cầu nhiều phần (nhưng có tài liệu đề xuất một số lựa chọn thay thế có thể).
Nếu bạn đang viết (hoặc gỡ lỗi) một thư viện để phân tích cú pháp hoặc tạo dữ liệu thô, thì bạn cần bắt đầu lo lắng về định dạng. Bạn cũng có thể muốn biết về nó vì lợi ích.
application/x-www-form-urlencoded
ít nhiều giống với chuỗi truy vấn ở cuối URL.
multipart/form-data
phức tạp hơn đáng kể nhưng nó cho phép bao gồm toàn bộ tập tin trong dữ liệu. Một ví dụ về kết quả có thể được tìm thấy trong đặc tả HTML 4 .
text/plain
được giới thiệu bởi HTML 5 và chỉ hữu ích để gỡ lỗi - từ thông số kỹ thuật : Chúng không thể hiểu được bằng máy tính - và tôi cho rằng những cái khác kết hợp với các công cụ (như Bảng điều khiển mạng trong công cụ phát triển của hầu hết các trình duyệt) thì tốt hơn cho điều đó).
khi nào chúng ta nên sử dụng nó
Câu trả lời của Quentin là đúng: sử dụng multipart/form-data
nếu biểu mẫu có chứa tệp tải lên và application/x-www-form-urlencoded
nếu không, đó là mặc định nếu bạn bỏ qua enctype
.
Tôi sẽ:
Có ba khả năng cho enctype
:
application/x-www-form-urlencoded
multipart/form-data
(thông số kỹ thuật chỉ ra RFC7578 )text/plain
. Đây là "không đáng tin cậy bằng máy tính", vì vậy nó không bao giờ nên được sử dụng trong sản xuất và chúng tôi sẽ không nhìn sâu hơn vào nó.Khi bạn thấy một ví dụ về mỗi phương thức, nó sẽ trở nên rõ ràng về cách chúng hoạt động và khi nào bạn nên sử dụng từng phương thức.
Bạn có thể tạo các ví dụ bằng cách sử dụng:
nc -l
hoặc máy chủ ECHO: Máy chủ thử nghiệm HTTP chấp nhận các yêu cầu GET / POSTLưu biểu mẫu vào một .html
tệp tối thiểu :
<!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>
Chúng tôi thiết lập các giá trị văn bản mặc định aωb
, mà phương tiện aωb
vì ω
là U+03C9
, đó là các byte 61 CF 89 62
trong UTF-8.
Tạo tập tin để tải lên:
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
Chạy máy chủ echo nhỏ của chúng tôi:
while true; do printf '' | nc -l 8000 localhost; done
Mở HTML trên trình duyệt của bạn, chọn các tệp và nhấp vào gửi và kiểm tra thiết bị đầu cuối.
nc
in yêu cầu nhận được.
Đã thử nghiệm trên: Ubuntu 14.04.3, nc
BSD 1.105, Firefox 40.
Firefox đã gửi:
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--
Đối với tệp nhị phân và trường văn bản, các byte 61 CF 89 62
( aωb
trong UTF-8) được gửi theo nghĩa đen. Bạn có thể xác minh rằng với nc -l localhost 8000 | hd
, nói rằng các byte:
61 CF 89 62
đã được gửi ( 61
== 'a' và 62
== 'b').
Vì vậy, rõ ràng rằng:
Content-Type: multipart/form-data; boundary=---------------------------735323031399963166993862150
đặt loại nội dung thành multipart/form-data
và nói rằng các trường được phân tách bằng boundary
chuỗi đã cho .
Nhưng lưu ý rằng:
boundary=---------------------------735323031399963166993862150
có hai cha ít --
hơn rào cản thực tế
-----------------------------735323031399963166993862150
Điều này là do tiêu chuẩn yêu cầu ranh giới bắt đầu bằng hai dấu gạch ngang --
. Các dấu gạch ngang khác dường như là cách Firefox chọn để thực hiện ranh giới tùy ý. RFC 7578 đề cập rõ ràng rằng hai dấu gạch ngang hàng đầu đó --
là bắt buộc:
4.1. "Ranh giới" Tham số của nhiều dữ liệu / biểu mẫu
Cũng như các loại nhiều phần khác, các phần được phân định bằng dấu phân cách ranh giới, được xây dựng bằng CRLF, "-" và giá trị của tham số "ranh giới".
mỗi trường có một số tiêu đề phụ trước dữ liệu của nó : Content-Disposition: form-data;
, trường name
, the filename
, theo sau là dữ liệu.
Máy chủ đọc dữ liệu cho đến chuỗi ranh giới tiếp theo. Trình duyệt phải chọn một ranh giới sẽ không xuất hiện trong bất kỳ trường nào, vì vậy đây là lý do tại sao ranh giới có thể khác nhau giữa các yêu cầu.
Bởi vì chúng tôi có ranh giới duy nhất, không cần mã hóa dữ liệu: dữ liệu nhị phân được gửi như hiện có.
TODO: kích thước ranh giới tối ưu ( log(N)
tôi đặt cược) và tên / thời gian chạy của thuật toán tìm thấy nó là gì? Đã hỏi tại: /cs/39487/find-the-shortest- resultence-that-is-not-a-sub-resultence-of-a-set-of- result
Content-Type
được tự động xác định bởi trình duyệt.
Làm thế nào nó được xác định chính xác đã được hỏi tại: Làm thế nào loại mime của một tệp tải lên được xác định bởi trình duyệt?
Bây giờ thay đổi enctype
thành application/x-www-form-urlencoded
, tải lại trình duyệt và gửi lại.
Firefox đã gửi:
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
Rõ ràng dữ liệu tệp không được gửi, chỉ có các tên cơ sở. Vì vậy, điều này không thể được sử dụng cho các tập tin.
Đối với trường văn bản, chúng tôi thấy rằng các ký tự có thể in thông thường như a
và b
được gửi trong một byte, trong khi các ký tự không in được như thế 0xCF
và 0x89
chiếm 3 byte mỗi ký tự : %CF%89
!
Tải lên tệp thường chứa nhiều ký tự không in được (ví dụ hình ảnh), trong khi các hình thức văn bản hầu như không bao giờ thực hiện.
Từ các ví dụ chúng ta đã thấy rằng:
multipart/form-data
: thêm một vài byte chi phí biên cho thông báo và phải dành một chút thời gian để tính toán nó, nhưng sẽ gửi mỗi byte trong một byte.
application/x-www-form-urlencoded
: có một ranh giới byte đơn trên mỗi trường ( &
), nhưng thêm hệ số chi phí tuyến tính là 3x cho mỗi ký tự không in được.
Do đó, ngay cả khi chúng tôi có thể gửi tệp cùng application/x-www-form-urlencoded
, chúng tôi sẽ không muốn, vì nó rất kém hiệu quả.
Nhưng đối với các ký tự có thể in được tìm thấy trong các trường văn bản, nó không quan trọng và tạo ra ít chi phí hơn, vì vậy chúng tôi chỉ sử dụng nó.
%CF
dài 3 byte: %
, C
và F
:-) Story of khiến người dùng không thể đọc được.
nc
sẽ không chấp nhận đồng thời cả đối số -l
và -p
đối số. Nhưng điều này làm việc cho tôi : while true; do printf '' | nc -l 8000; done
.
Content-Type
có hai dấu gạch nối ( --
) ít hơn, tức là khi thực sự sử dụng ranh giới trong nội dung thư, bạn phải đặt tiền tố cho nó --
. Ngoài ra, ranh giới cuối cùng phải được thêm vào --
, nhưng điều đó đủ dễ nhận thấy. Xem stackoverflow.com/questions/3508252/
enctype='multipart/form-data
là một loại mã hóa cho phép các tệp được gửi qua POST . Rất đơn giản, không có mã hóa này, các tệp có thể được gửi qua POST .
Nếu bạn muốn cho phép người dùng tải lên một tập tin thông qua một hình thức, bạn phải sử dụng này enctype .
multipart/form-data
để gửi các tệp không nhị phân nhưng nó không hiệu quả. Tôi tin rằng sử dụng application/x-www-form-urlencoded
là cách chính xác để gửi dữ liệu không nhị phân nhưng ai đó có nhiều kinh nghiệm hơn với các tệp không nhị phân có thể cần phải sửa cho tôi.
multipart/form-data
để gửi tệp là nó sẽ hoạt động tự động trong cả frontend và backend. Bạn không phải thực hiện bất kỳ xử lý đặc biệt. Tất cả các tệp là nhị phân ngay cả khi chúng chỉ nên chứa văn bản. application/x-www-form-urlencoded
là cách tiêu chuẩn để POST một biểu mẫu mà không có tệp đính kèm. multipart/form-data
là cách tiêu chuẩn để POST một biểu mẫu với (các) tệp đính kèm. (Ngoài ra còn có rất nhiều bảng mã khác, chẳng hạn như application/json
và application/json-patch+json
, thường dùng để liên lạc giữa máy chủ và máy khách.)
multipart/form-data
. Những gì bạn không thể làm là làm điều đó bằng cách sử dụng một biểu mẫu HTML thông thường, không có JavaScript. Đặt biểu mẫu để sử dụng multipart/form-data
là cơ chế duy nhất mà HTML cung cấp để cho phép bạn POST các tệp mà không cần sử dụng JavaScript. Tôi cảm thấy như điều này không đủ rõ ràng trong câu trả lời và rằng một người đọc ngây thơ có thể nghĩ rằng việc không thể gửi tệp mà không có multipart/form-data
giới hạn của HTTP ; không phải vậy
Khi gửi biểu mẫu, bạn yêu cầu trình duyệt của mình gửi, thông qua giao thức HTTP, một thông báo trên mạng, được bao bọc đúng cách trong cấu trúc thông báo giao thức TCP / IP. Một trang HTML có một cách để gửi dữ liệu đến máy chủ: bằng cách sử dụng <form>
s.
Khi một biểu mẫu được gửi, Yêu cầu HTTP được tạo và gửi đến máy chủ, thông báo sẽ chứa tên trường trong biểu mẫu và các giá trị được điền bởi người dùng. Việc truyền này có thể xảy ra với POST
hoặc GET
các phương thức HTTP .
POST
yêu cầu trình duyệt của bạn xây dựng một thông điệp HTTP và đặt tất cả nội dung vào phần thân của thông điệp (một cách làm rất hữu ích, an toàn hơn và cũng linh hoạt hơn).GET
sẽ gửi dữ liệu biểu mẫu trong chuỗi truy vấn . Nó có một số hạn chế về biểu diễn dữ liệu và độ dài.Thuộc tính chỉ enctype
có ý nghĩa khi sử dụng POST
phương pháp. Khi được chỉ định, nó sẽ hướng dẫn trình duyệt gửi biểu mẫu bằng cách mã hóa nội dung của nó theo một cách cụ thể. Từ MDN - Mẫu mã :
Khi giá trị của thuộc tính phương thức là post, enctype là loại nội dung MIME được sử dụng để gửi biểu mẫu đến máy chủ.
application/x-www-form-urlencoded
: Đây là mặc định. Khi biểu mẫu được gửi, tất cả tên và giá trị được thu thập và Mã hóa URL được thực hiện trên chuỗi cuối cùng.multipart/form-data
: Ký tự KHÔNG được mã hóa. Điều này rất quan trọng khi biểu mẫu có kiểm soát tải lên tệp. Bạn muốn gửi tệp nhị phân và điều này đảm bảo rằng dòng bit không bị thay đổi.text/plain
: Spaces được chuyển đổi, nhưng không thực hiện thêm mã hóa.Khi gửi biểu mẫu, một số lo ngại về bảo mật có thể phát sinh như được nêu trong RFC 7578 Phần 7: Dữ liệu biểu mẫu nhiều phần - Cân nhắc bảo mật :
Tất cả các phần mềm xử lý biểu mẫu phải xử lý dữ liệu biểu mẫu do người dùng cung cấp
có độ nhạy, vì phần mềm này thường chứa
thông tin nhận dạng cá nhân hoặc bí mật . Việc sử dụng rộng rãi các tính năng "tự động điền" trong các trình duyệt web; chúng có thể được sử dụng để lừa người dùng
vô tình gửi thông tin bí mật khi hoàn thành
các nhiệm vụ vô hại. nhiều dữ liệu / biểu mẫu dữ liệu không cung cấp bất kỳ tính năng nào
để kiểm tra tính toàn vẹn, đảm bảo tính bảo mật, tránh
sự nhầm lẫn của người dùng hoặc các tính năng bảo mật khác; những mối quan tâm đó phải được
giải quyết bằng các ứng dụng điền biểu mẫu và giải thích dữ liệu biểu mẫu.Các ứng dụng nhận biểu mẫu và xử lý chúng phải cẩn thận không cung cấp dữ liệu trở lại trang web xử lý biểu mẫu yêu cầu không được gửi.
Điều quan trọng là khi diễn giải tên tệp của trường
tiêu đề Nội dung để không vô tình ghi đè lên các tệp trong
không gian tệp của người nhận.
Điều này liên quan đến bạn nếu bạn là nhà phát triển và máy chủ của bạn sẽ xử lý các biểu mẫu được gửi bởi người dùng có thể chứa thông tin nhạy cảm.
enctype
phải làm gì. Tôi biết đó là nghĩa đen từ multipart/form-data
RFC, nhưng dù sao đó cũng là một sự cân nhắc về bảo mật tùy ý về việc gửi các biểu mẫu hoàn toàn trực giao cho dù dữ liệu được gửi dưới dạng application/x-www-form-urlencoded
hay multipart/form-data
.
enctype='multipart/form-data'
có nghĩa là không có ký tự sẽ được mã hóa. đó là lý do tại sao loại này được sử dụng trong khi tải tệp lên máy chủ.
Vì vậy, multipart/form-data
được sử dụng khi một biểu mẫu yêu cầu dữ liệu nhị phân, như nội dung của tệp, được tải lên
Đặt thuộc tính phương thức thành POST vì nội dung tệp không thể được đặt trong tham số URL bằng biểu mẫu.
Đặt giá trị của kiểu mã hóa thành nhiều dữ liệu / biểu mẫu dữ liệu vì dữ liệu sẽ được chia thành nhiều phần, một phần cho mỗi tệp cộng với một phần cho văn bản của phần thân biểu mẫu có thể được gửi cùng với chúng.
POST
có khả năng là đủ để gửi tệp qua biểu mẫu và việc thêm multipart/form-data
chỉ là một phần thưởng theo một cách mơ hồ nào đó. Đó không phải là trường hợp. Hầu hết các tập tin sẽ hoàn toàn yêu cầu sử dụng multipart/form-data
.
<head>
và <body>
không liên quan và khó hiểu.
Thông thường đây là khi bạn có một biểu mẫu POST cần lấy tệp tải lên dưới dạng dữ liệu ... điều này sẽ cho máy chủ biết cách mã hóa dữ liệu được truyền, trong trường hợp đó nó sẽ không được mã hóa bởi vì nó sẽ chỉ truyền và tải lên các tệp đến máy chủ, ví dụ như khi tải lên hình ảnh hoặc pdf
Thuộc tính enctype chỉ định cách mã hóa dữ liệu biểu mẫu khi gửi nó đến máy chủ.
Thuộc tính enctype chỉ có thể được sử dụng nếu phương thức = "bài".
Không có ký tự được mã hóa. Giá trị này là bắt buộc khi bạn đang sử dụng các biểu mẫu có kiểm soát tải lên tệp
Từ W3Schools
multipart/form-data
. Nó cũng không rõ ràng lắm; Câu "Không có ký tự được mã hóa" nghĩa là gì? -1.