Enctype = 'Multipart / form-data' nghĩa là gì?


Câu trả lời:


1570

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

  • Không bao giờ sử dụng text/plain.

Khi bạn đang viết mã phía máy khách:

  • sử dụng multipart/form-datakhi biểu mẫu của bạn bao gồm bất kỳ <input type="file">yếu tố nào
  • nếu không bạn có thể sử dụng multipart/form-datahay application/x-www-form-urlencodednhưng application/x-www-form-urlencodedsẽ hiệu quả hơn

Khi bạn đang viết mã phía máy chủ:

  • Sử dụng thư viện xử lý biểu mẫu được viết sẵn

Hầu hết (chẳng hạn như Perl's CGI->paramhoặ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-dataphứ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 đó).


5
@Quentin Xin lỗi, điều gì sẽ xảy ra nếu chúng ta sử dụng nhiều phần cho tất cả các hình thức? với và xóa các tập tin.
Webinan

12
Nó không có ý nghĩa đối với các biểu mẫu GET và nó làm cho kích thước tệp yêu cầu lớn hơn.
Quentin

@Quentin mặc định dữ liệu biểu mẫu nhiều lần gửi dưới dạng luồng?
Growler

Liệu enc trong enctype có nghĩa là gì?
Philip Rego

1
"Các biểu mẫu HTML cung cấp ba phương pháp đánh dấu ENC "
Quentin

449

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-datanếu biểu mẫu có chứa tệp tải lên và application/x-www-form-urlencodednếu không, đó là mặc định nếu bạn bỏ qua enctype.

Tôi sẽ:

  • thêm một số tài liệu tham khảo HTML5
  • giải thích lý do tại sao anh ta đúng với một ví dụ gửi mẫu

Tài liệu tham khảo HTML5

ba khả năng cho enctype:

Cách tạo các ví dụ

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:

Lưu biểu mẫu vào một .htmltệ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&#x03C9;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&#x03C9;b, mà phương tiện aωbωU+03C9, đó là các byte 61 CF 89 62trong 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, ncBSD 1.105, Firefox 40.

nhiều dữ liệu / biểu mẫu

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ωbtrong 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-datavà nói rằng các trường được phân tách bằng boundarychuỗ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?

application / x-www-form-urlencoding

Bây giờ thay đổi enctypethà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ư abđược gửi trong một byte, trong khi các ký tự không in được như thế 0xCF0x89chiếm 3 byte mỗi ký tự : %CF%89!

So sánh

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ính3x 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ó.


3
@ Khanna111 %CFdài 3 byte: %, CF:-) Story of khiến người dùng không thể đọc được.
Ciro Santilli 冠状 病毒 审查 事件

6
Trên OS X, ncsẽ không chấp nhận đồng thời cả đối số -l-pđối số. Nhưng điều này làm việc cho tôi : while true; do printf '' | nc -l 8000; done.
PhilipS

4
Một điểm nhỏ nhưng quan trọng không được đề cập là ranh giới được chỉ định trong Content-Typecó 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/
Bernard

1
Theo như tôi có thể nói, quan điểm của việc đặt BẤT K D LÚC NÀO vào ranh giới là làm cho không thể kiểm tra cú pháp của yêu cầu bằng mắt. Vui lòng không sử dụng chúng trong mã thông báo ranh giới của bạn.
Dewi Morgan

1
@DewiMorgan Bạn hoàn toàn đúng. Tôi đã chỉnh sửa bài đăng và xóa dấu gạch ngang khỏi chuỗi ranh giới.
Tối đa

91

enctype='multipart/form-datalà 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 .


Vì vậy, nếu tập tin không phải là tập tin nhị phân thì chúng ta có thể làm việc mà không có điều này không?
Joly Julum

Từ những gì tôi hiểu, bạn có thể sử dụng 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-urlencodedlà 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.
Matt Asbury

11
Ưu điểm chính của việc sử dụng 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-urlencodedlà cách tiêu chuẩn để POST một biểu mẫu mà không có tệp đính kèm. multipart/form-datalà 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/jsonapplication/json-patch+json, thường dùng để liên lạc giữa máy chủ và máy khách.)
Daniel Luna

6
Giá trị của nó chỉ ra rằng bạn có thể mã hóa 64 hình ảnh của bạn và gửi nó dưới dạng dữ liệu chuỗi đơn giản.
James

3
Thêm vào nhận xét của @ Prospero ở trên: bạn hoàn toàn có thể gửi tệp qua POST mà không cần sử dụng 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-datalà 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-datagiới hạn của HTTP ; không phải vậy
Đánh dấu Amery

81

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 POSThoặ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).
  • GETsẽ 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.

Nêu cách gửi biểu mẫu của bạn đến máy chủ

Thuộc tính chỉ enctypecó ý nghĩa khi sử dụng POSTphươ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.

Bảo vệ

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.


1
Các công cụ về bảo mật sau lần chỉnh sửa gần đây nhất đều không liên quan đến câu hỏi enctypephải làm gì. Tôi biết đó là nghĩa đen từ multipart/form-dataRFC, 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-urlencodedhay multipart/form-data.
Đánh dấu Amery

38

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


8

Đặ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.


Điều này ngụ ý rằng POSTcó khả năng là đủ để gửi tệp qua biểu mẫu và việc thêm multipart/form-datachỉ 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.
gạch dưới

1
  • thuộc tính enctype ( ENC ode TYPE ) chỉ định cách mã hóa dữ liệu biểu mẫu khi gửi nó đến máy chủ.
  • Multipart / form-data là một trong những giá trị của thuộc tính enctype, được sử dụng trong phần tử biểu mẫu có tải lên tệp. đa phần có nghĩa là dữ liệu biểu mẫu chia thành nhiều phần và gửi đến máy chủ.

5
Tôi tin rằng enctype không đại diện cho loại mã hóa. Không có mã hóa liên quan ở cấp độ này. Tôi đoán là loại mã hóa hoặc loại kèm theo. Nhưng chắc chắn nó không phải là loại mã hóa.
Yeo

1
Điểm đạn cuối cùng của bạn ở đây về <head><body>không liên quan và khó hiểu.
Đánh dấu Amery

0

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


-3

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


2
Trích dẫn này thậm chí không đề cập đến 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.
Đánh dấu Amery
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.