Công cụ dành cho nhà phát triển · Bộ mã hóa và giải mã URL
Tại sao + trở thành khoảng trắng khi bạn giải mã chuỗi truy vấn và khi thì không
· Cách thức hoạt động
url-encoding javascript developer-workflow
Việc + có nghĩa là không gian hay không tùy thuộc vào bộ giải mã bạn gọi. Bài đăng này giải thích cách giải mãURIComponent, URLSearchParams và các khung máy chủ xử lý từng dấu + và cách tránh biến dấu cộng thực sự thành khoảng trắng.
Tại sao + trở thành khoảng trắng khi bạn giải mã chuỗi truy vấn và khi thì không
HTML việc gửi biểu mẫu sử dụng định dạng application/x-www-form-urlencoded, trong đó khoảng trống trở thành dấu cộng. Máy chủ nhận name=Alice+Smith thay thế mỗi dấu cộng bằng dấu cách trước khi trích xuất giá trị. Khi một dấu cộng thực sự thuộc về dữ liệu, chẳng hạn như trong phép tính 5+3, nó sẽ đến máy chủ dưới dạng 5 3 sau bước giải mã biểu mẫu. Sự chuyển đổi vô hình này là gốc rễ của sự nhầm lẫn.
Việc giải mã JavaScript tạo ra các kết quả khác nhau tùy thuộc vào chức năng bạn sử dụng. URLSearchParams coi dấu cộng là không gian, phù hợp với hành vi của máy chủ. Nhưng việc giải mãURIComponent vẫn giữ nguyên, xử lý nó theo nghĩa đen. Sự bất đối xứng giữa các chức năng này là lý do tại sao cùng một đầu vào lại giải mã khác nhau. Một nhà phát triển mong đợi cả hai bộ giải mã đều tạo ra kết quả giống nhau nhưng lại phát hiện ra rằng không phải vậy.
Hai mã hóa trông giống nhau — RFC 3986 mã hóa phần trăm so với ứng dụng/x-www-form-urlencoded
Hai tiêu chuẩn mã hóa trông giống nhau nhưng hoạt động khác nhau. RFC 3986 xác định mã hóa phần trăm: bất kỳ ký tự nào trở thành %HH. Không gian trở thành %20. Tiêu chuẩn application/x-www-form-urlencoded thêm một cách viết tắt: dấu cách có thể là dấu cộng. Hoặc hoạt động trong ngữ cảnh biểu mẫu, nhưng dấu cộng là tùy chọn và dành riêng cho tiêu chuẩn đó. Chúng là những miền khác nhau có hình dáng tương tự nhau.
Việc gọi giải mãURIComponent chỉ áp dụng giải mã RFC 3986. Nó đọc %20 là dấu cách và dấu cộng là dấu cộng theo nghĩa đen. URLSearchParams áp dụng các quy tắc giải mã biểu mẫu: số thoát phần trăm trở thành ký tự của chúng và dấu cộng trở thành khoảng trắng. Hai hàm này giải quyết cùng một vấn đề trong các miền khác nhau. Việc trộn lẫn chúng sẽ làm cho một dấu cộng thực sự biến mất hoặc một khoảng trống trở thành dấu cộng và không thể chuyển đổi.
giải mãURIComponent lá + một mình; URLSearchParams biến nó thành một khoảng trắng — so sánh hai hành vi JavaScript
Hoạt động của máy chủ khác nhau, điều này làm phức tạp thêm vấn đề. Rails hoặc Django tự động áp dụng quy tắc biểu mẫu: dấu cộng trở thành dấu cách. Tuy nhiên, việc trích xuất và giải mã thủ công chuỗi truy vấn thô bằng bộ giải mã URL vẫn giữ nguyên. Cùng một giá trị được xử lý bởi các khung khác nhau sẽ tạo ra các kết quả khác nhau. Mã máy chủ thường xử lý việc này một cách ngầm định, ẩn vấn đề cho đến khi bạn viết bộ giải mã tùy chỉnh.
Ví dụ: trường số điện thoại lưu trữ +1-555-0100 với dấu cộng là mã quốc gia. Biểu mẫu HTML mã hóa nó thành %2B1-555-0100 vì JavaScript được mã hóa cộng với %2B. Máy chủ nhận được điều này. Nếu nó áp dụng giải mã biểu mẫu, %2B sẽ trở thành dấu cộng và giá trị là chính xác. Nếu proxy loại bỏ mã hóa, việc gọi giải mãURIComponent trên kết quả sẽ tạo ra +1-555-0100. Mỗi lớp giải mã một lần.
Máy chủ làm gì - hành vi chung của khung trong chuỗi truy vấn và nội dung yêu cầu, được mô tả bằng thuật ngữ chung
JavaScript có thể mã hóa các giá trị bằng EncodeURIComponent. Cho a+b, nó tạo ra a%2Bb. Khi chuỗi được mã hóa đó đến máy chủ hoặc bộ giải mã nhận biết biểu mẫu, %2B sẽ giải mã thành dấu cộng và kết quả là chính xác. Thay vào đó, nếu bạn mã hóa bằng quy tắc biểu mẫu thì dấu cách sẽ trở thành dấu cộng và dấu cộng thực sẽ trở thành %2B. Dù bằng cách nào, mã hóa sẽ tạo ra%2Bb. Việc giải thích phụ thuộc vào quy tắc giải mã nào được áp dụng.
Kiểm tra chuyến đi khứ hồi: bắt đầu bằng a+b. Mã hóa bằng EncodeURIComponent để nhận%2Bb. Giải mã a%2Bb bằng decodeURIComponent và khôi phục a+b. Chuyển a+b tới URLSearchParams: nó coi dấu cộng là khoảng trắng, tạo ra a b. Chuyển a%2Bb tới URLSearchParams để lấy lại a+b. Cùng một đầu vào được giải mã theo hai cách sẽ tạo ra các đầu ra khác nhau tùy thuộc vào bộ giải mã bạn sử dụng.
Ví dụ hoạt động: 'a+b' và 'a%2Bb' thông qua cả hai bộ giải mã — bốn kết quả trong một bảng
Những lỗi phổ biến xảy ra trực tiếp. Một nhà phát triển giải mã bằng decodeURIComponent và thắc mắc tại sao dữ liệu biểu mẫu đến có dấu cộng thực lại bị ngắt. Lẽ ra họ nên sử dụng URLSearchParams. Ngược lại, ai đó sử dụng URLSearchParams khi họ nên sử dụng giải mãURIComponent và mọi dấu cộng theo nghĩa đen sẽ biến mất. Mã hóa hai lần tạo ra %252B, yêu cầu các cặp bộ mã hóa-giải mã phù hợp để giải mã chính xác.
Một lỗi khác là tạo chuỗi truy vấn bằng tay dưới dạng ?q=value mà không mã hóa. Bất kỳ dấu và hoặc bằng nào trong giá trị đều tự động tạo ra một tham số mới. Trình duyệt không đoán phép nối thứ hai; nó xử lý kết quả như được hình thành đúng cách. Chỉ mã hóa có chủ ý với EncodeURIComponent mới ngăn chặn được điều này. Bộ mã hóa và giải mã URL hiển thị cả ba chức năng, cho biết kết quả mà mỗi chức năng tạo ra.
Các lỗi phổ biến - giải mã hai lần hoặc mã hóa khoảng trắng dưới dạng + trong đoạn đường dẫn
Quy tắc mã hóa biểu mẫu được gọi là application/x-www-form-urlencoded vì nó mô tả tiêu đề Kiểu nội dung của nội dung yêu cầu HTTP. HTML biểu mẫu không có tệp tải lên sẽ gửi nội dung ở định dạng này. Chuỗi truy vấn trong URL cũng sử dụng quy ước này, mặc dù về mặt kỹ thuật chúng không có tiêu chuẩn mã hóa chính thức. Thông số kỹ thuật URL coi truy vấn là không rõ ràng; ý nghĩa cộng không bắt buộc. Nhưng trong các ứng dụng web, dấu cộng thường có nghĩa là không gian.
Để đảm bảo hành vi đúng, hãy mã hóa và giải mã có chủ ý bằng chức năng khớp. Nếu bạn đã mã hóa bằng EncodeURIComponent, hãy giải mã bằng DecodeURIComponent. Nếu đọc dữ liệu biểu mẫu HTML hoặc nội dung yêu cầu ở định dạng biểu mẫu, hãy sử dụng URLSearchParams. Đừng bao giờ đoán dựa vào ngoại hình. Một chuỗi như a+b là chuỗi không rõ ràng. Bộ giải mã không thể hoán đổi cho nhau.
Điều này không bao gồm những gì - dữ liệu biểu mẫu nhiều phần và JSON nội dung yêu cầu
Dữ liệu biểu mẫu nhiều phần, nội dung yêu cầu JSON và các tiêu chuẩn khác có quy tắc mã hóa riêng. JSON không sử dụng dấu cộng cho dấu cách hoặc mã hóa phần trăm; nó sử dụng lối thoát Unicode. Multipart sử dụng các ranh giới khác nhau. Bài viết này chỉ đề cập đến các chuỗi truy vấn và nội dung được mã hóa biểu mẫu vì đó là nơi xuất hiện dấu cộng không rõ ràng. Luôn kiểm tra tiêu đề Content-Type và RFC xác định nó.
Luôn mã hóa một dấu cộng bằng chữ dưới dạng %2B khi nó thuộc về một giá trị truy vấn. Bộ mã hóa và giải mã URL hiển thị cách dấu cộng được bảo vệ dưới dạng %2B trong chế độ thành phần, tách biệt với các khoảng trắng trở thành %20. Chuyển a+b và a%2Bb qua từng chế độ, sau đó kiểm tra kết quả. Sự so sánh đó cho thấy tại sao cùng một đầu vào lại giải mã khác nhau. Sự khác biệt là hành vi đúng đắn của hai tiêu chuẩn khác nhau.
Bài học rút ra: luôn mã hóa một dấu cộng bằng chữ dưới dạng% 2B - cách bộ mã hóa và giải mã URL hiển thị giá trị trông như thế nào dưới dạng giá trị truy vấn được mã hóa phần trăm
Bài học rút ra: dấu cộng trong chuỗi truy vấn là dạng viết tắt mã hóa cho khoảng trắng, không phải dấu cộng theo nghĩa đen, trừ khi nó xuất phát từ mã hóa bảo vệ nó dưới dạng %2B. Bộ giải mã sai sẽ mất khả năng bảo vệ đó. URLSearchParams an toàn nhất trong JavaScript hiện đại; nó xử lý mã hóa biểu mẫu và cấp quyền truy cập tham số được đặt tên. Đối với chuỗi thô, EncodeURIComponent bảo vệ mọi thứ; giải mãURIComponent diễn giải %20 và phần trăm nhưng xử lý dấu cộng theo nghĩa đen.
Kiểm tra điều này: xây dựng ?x=a+b bằng tay và dán vào bộ mã hóa & giải mã URL. Kiểm tra nó và xem URLSearchParams chia nó thành tham số x với giá trị a b. Dán ?x=a%2Bb và xem giá trị a+b. Sử dụng EncodeURIComponent để xây dựng URL và so sánh. Xác nhận trực quan đó làm rõ quy tắc: quy tắc biểu mẫu sử dụng dấu cộng, mã hóa phần trăm sử dụng %20, việc trộn chúng là lý do khiến dấu cộng biến mất trong không gian.