- Chris Morgan đã quyết định chặn hoàn toàn các chuỗi truy vấn không được phép trên trang web của mình, và phần triển khai hiện nằm trong Caddyfile
- Ông không muốn các tham số dùng để theo dõi như
?ref=example.com bị gắn vào URL của mình, và cho rằng nếu cần thì chỉ cần xem header Referer
- Ông cho rằng UTM parameters như
?utm_source=example&utm_*&c.* là thứ để chủ sở hữu website sử dụng, không phải để bên ngoài tự ý gắn vào
- Hiện tại website này hoàn toàn không dùng chuỗi truy vấn, và nếu sau này có dùng thì ông chỉ định cho phép các tham số đã biết
- URL cuối cùng được chọn là
/no-query-strings, còn /%3F thì không được chọn vì có vấn đề với việc ghi lại try_files của Caddy
Chặn chuỗi truy vấn không được phép
- Chris Morgan đã quyết định chặn hoàn toàn các chuỗi truy vấn không được phép trên trang web của mình
- Ông không muốn các tham số dùng để theo dõi như
?ref=example.com bị gắn vào URL của mình, và cho rằng nếu cần thì chỉ cần xem header Referer
- Ông cho rằng UTM parameters như
?utm_source=example&utm_*&c.* là thứ để chủ sở hữu website sử dụng, không phải để bên ngoài tự ý gắn vào
- Hiện tại trang web này hoàn toàn không dùng chuỗi truy vấn, và nếu sau này có dùng thì ông chỉ định cho phép các tham số đã biết
- Trước đây ông từng dùng các URL vô hiệu hóa bộ nhớ đệm như
?t=…, ?h=… cho URL stylesheet, nhưng ông cho rằng việc các yêu cầu đó bị hỏng cũng không sao
- Việc chặn này hiện đã được triển khai trong Caddyfile
Quá trình chọn URL
-
Kế hoạch dùng /?
- Ban đầu ông rất muốn đăng trang này tại
https://chrismorgan.info/?
- Vì đây là dạng đường dẫn rỗng và truy vấn rỗng, nó sẽ phá vỡ khá nhiều giả định phổ biến nhưng sai lầm, và có thể khiến một số công cụ lúng túng
curl dường như đã tự ý xóa dấu hỏi ở cuối trên dòng lệnh, còn việc dùng qua thư viện thì ông chưa thử
- Cuối cùng ông quyết định tôn trọng khái niệm đường dẫn và dễ dãi hơn với mọi người, nhất là khi ông cho rằng mình đã ép Caddy đi theo hướng đủ phiền toái rồi
-
Kế hoạch dùng /%3F
-
Lựa chọn cuối cùng
- URL cuối cùng được chọn là
/no-query-strings
/? hoặc /%3F có thể sẽ được dùng sau này cho mục đích khác liên quan đến chuỗi truy vấn
1 bình luận
Ý kiến trên Hacker News
Tôi tò mò nên xem lại tiêu chuẩn W3C về HTML và URL, và khá bất ngờ là định dạng chuỗi truy vấn thực ra không được định nghĩa riêng ngoài percent-encoding
Có thể nhầm chuỗi truy vấn với chuỗi truy vấn “form-urlencoded”[0], nhưng đó chỉ là một trong những định dạng có thể tương tác với nhau. Nói chung, chuỗi truy vấn là một chuỗi percent-encoded tùy ý[1] xuất hiện sau dấu
?trong URL, và là một thuộc tính khác của đối tượngURLtrong HTML có thể dùng để tạo phản hồiĐối tượng
URLSearchParamslà kết quả của việc phân tích chuỗi truy vấn bằng bộ phân tích form-urlencoded, nhưng đó chỉ là một lớp tương thích cho JavaScriptThành thật mà nói, trước khi xem tiêu chuẩn tôi đã chuẩn bị để phản đối, nhưng tiêu chuẩn khá rõ ràng. Phản hồi bằng 404 với chuỗi truy vấn không mong đợi cũng có thể là phù hợp. Chuỗi truy vấn cũng là một phần của API URL giống như đường dẫn, và hầu hết mọi người có lẽ sẽ đồng ý rằng việc nối thêm chuỗi tùy ý vào đường dẫn là không tốt và là hành vi không được định nghĩa
[0]: https://url.spec.whatwg.org/#application/x-www-form-urlencod...
[1]: https://url.spec.whatwg.org/#url-class
index.php, rồi xử lý toàn bộ định tuyến bằng chuỗi truy vấnTất nhiên là theo định dạng form-urlencoded, con người cũng đâu phải dân mọi rợ. Thế nên sẽ có các URL như
index.php?p=home,index.php?p=shop, hoặcindex.php?action=showthread&forum=42&thread=17976. Trong cấu trúc như vậy, việc trả về 404 cho tham số truy vấn không xác định là phản hồi đúng đắn hiện ra rất rõThực tế bây giờ vẫn còn nhiều trang hoạt động như vậy, chỉ là được giấu sau vài quy tắc rewrite của Apache/nginx vì SEO
Rốt cuộc URL chỉ là một chuỗi mà máy chủ quyết định sẽ xử lý như thế nào
Điều thực sự buồn cười trong cuộc tranh luận này là mọi người lo về tác dụng phụ của việc trả về 404 nhưng lại hoàn toàn quên mất lịch sử web đã có một thời gian rất dài mà đường dẫn gần như vô nghĩa. Giờ thì đường dẫn đã thắng. Gần như không còn ai bắt đầu mới với URL kiểu
/item?id=…nữa. Tốt đấy!Nó mang nghĩa “hãy sửa yêu cầu rồi thử lại”, và tôi cũng dùng như vậy trong API mình cung cấp. Tôi thích nó hơn 406 vì đây không phải vấn đề phía tôi không xử lý được. Nếu ai đó cố thêm gì đó vào chuỗi truy vấn để làm hỏng nó hoặc không tạo yêu cầu đúng theo tài liệu, thì đó là trách nhiệm của bên gửi yêu cầu
https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/...
Ví dụ từ góc độ cache, có thể coi
url?a=b&c=dlà tương đương vớiurl?c=d&a=bCó rất nhiều tập quán chưa từng được ghi thành tiêu chuẩn chính thức nhưng nếu không làm theo thì sẽ hỏng trên diện rộng, và cũng có rất nhiều “tiêu chuẩn” mà nếu bám sát từng chữ thì lại thành ngớ ngẩn
Trong trường hợp của bài viết gốc, thứ bị hỏng chỉ là trải nghiệm của người định vào trang đó, và có lẽ họ sẽ nhấn nút quay lại trên trình duyệt rồi tiếp tục việc của mình. Có chấp nhận mức thiệt hại đó hay không là quyết định của chính họ. Chỉ vì không tiêu chuẩn nào cấm thì không có nghĩa là theo định nghĩa nó được phép, và ngược lại, tiêu chuẩn cấm cũng không có nghĩa là đột nhiên tuyệt đối không được phép
Theo cách tôi hiểu thì có vẻ tác giả bực mình vì các website khác gắn thêm chuỗi truy vấn như
?ref=origin.comvào liên kết dẫn đến trang của tác giảTôi không hiểu việc đó mang lại lợi ích gì cho trang nguồn và gây hại gì cho trang của tác giả
Hành vi của cả hai bên đều hoàn toàn khó hiểu
Tôi hiểu trường hợp khi chạy chiến dịch quảng cáo thì Google gắn chuỗi truy vấn UTM để theo dõi người dùng đến từ chiến dịch nào. Khi đó bên nguồn và bên đích đang hợp tác với nhau. Nhưng ở đây bên nguồn lại tự ý gắn thêm gì đó chẳng vì lý do gì. Tại sao vậy?
xyz.comtrong chuỗi truy vấnref, rồi nghĩ rằng có thể quảng cáo ở đó hoặc hợp tác liên kết với trang đóThành thật mà nói, với các trang ngách/startup thì điều này khá hữu ích. Tôi đã từng ở cả hai phía của những cuộc trao đổi bắt đầu từ việc nhìn thấy giá trị này trong công cụ phân tích web: có lần tôi chủ động liên hệ sau khi thấy traffic giới thiệu, lần khác thì chính trang tôi gắn liên kết đã liên hệ với tôi. Cả hai lần đều kết thúc thành quan hệ hợp tác có lợi cho đôi bên
Tôi cũng phần nào hiểu luận điểm về quyền riêng tư, nhưng nó không cung cấp nhiều thông tin hơn header
Referertiêu chuẩn. Chỉ là nếu dùng các công cụ phân tích như Simple Analytics/Plausible thì nó dễ thấy hơn nhiềuViệc thêm chuỗi truy vấn thường được dùng cho mục đích theo dõi. Chỉ riêng việc tồn tại các tính năng như “copy clean link” của Firefox hay Enhanced Tracking Protection chủ động loại bỏ một số tham số UTM cũng cho thấy rất nhiều người không muốn điều đó
Có những trang sẵn sàng tham gia vào cái tôi tạm gọi là “nền kinh tế theo dõi”. Bởi vì bên nhận có thể nhìn log và thấy nhiều người đến từ trang của họ, rồi hành động theo hướng có lợi cho trang đó
Việc từ chối chuỗi truy vấn chỉ là một cách phản đối đơn giản đối với hệ thống đó
Đọc mô tả kiểu “một bảng điều khiển web nhỏ, phi tập trung, tự host, cho phép khách truy cập khám phá các website và trang thú vị do cộng đồng người vận hành website cá nhân độc lập đề xuất”, tôi nghĩ ngày xưa người ta gọi đó là Webring. Chỉ là không hoa mỹ đến vậy
Một trong những vấn đề tôi gặp khi phát triển framework ứng dụng mã nguồn mở là hosting dùng FastCGI không tôn trọng header
Auth, nên tôi buộc phải truyền token qua truy vấn. Rất dở ở chỗ khi sao chép/dán địa chỉ web thì token thường bị mang theo. Có thể giờ chuyện này đã được sửa rồiTrong backend do tôi kiểm soát và không cần công khai cho mọi người, tôi dùng header
Authà?Tôi muốn nghe giải thích chi tiết hơn về đoạn này. Về mặt kỹ thuật thì có vẻ như đang nói bản ghi
PARAMkhông thực sự đưa ra giá trị như mong đợiAnh ấy nói “vì vậy tôi quyết định thử một lệnh cấm toàn diện trên trang này: không có chuỗi truy vấn chưa được phê duyệt”, nhưng có vẻ trang của anh ta trả về 414 nếu yêu cầu có chứa truy vấn, và theo tôi đó là một lựa chọn sai
Nếu đây là hành động phản đối để bảo vệ người dùng, thì tại sao lại trừng phạt chính người dùng, những người ngay từ đầu có thể không kiểm soát được chuỗi đó?
Thay vào đó có lẽ nên dùng nó như một tín hiệu để chỉ cho người dùng cách họ có thể tự đưa ra quyết định này, chẳng hạn qua công cụ trình duyệt?
400 Bad Request, là mã lỗi client chung chung và đúng, nhưng không vui
402 Payment Required, thành thật mà nói nếu ai trả tiền để một URL cụ thể có chuỗi truy vấn hoạt động thì tôi cũng sẵn lòng
404 Not Found, nhưng quá dễ tạo ra tác dụng phụ và không truyền được cảm giác ‘định dạng yêu cầu bị sai’ mà tôi muốn
303 See Other không có header
Location. Ngày nay cực hiếm nhưng là hợp lệ. Ít nhất trong RFC 2616 là vậy (“The different URI SHOULD be given by the Location field in the response”). Nhưng trong 7231 và 9110 thì cách diễn đạt đã đổi theo hướng giả định sự tồn tại của headerLocation(“… as indicated by a URI in the Location header field”). Trong khi đó 301, 302, 307, 308 lại nói “the server SHOULD generate a Location header field”. Dù sao đi nữa, tôi vẫn thấy See Other không có headerLocationlà đủ ổn. Nhưng URI Too Long thì buồn cười hơn”https://chrismorgan.info/no-query-strings?foo
Ở đoạn “Bạn có thể cho rằng tôi đang lạm dụng 414 URI Too Long. Câu trả lời của tôi là cách này buồn cười hơn. Những lựa chọn khác tôi từng cân nhắc là...” thì một lựa chọn khác có thể là 418 I'm a teapot. Ấm trà thường cũng không hỗ trợ chuỗi truy vấn mà
Có vài lựa chọn nhìn qua thì hợp lý nhưng xem kỹ lại không phải: 406 “Not Acceptable” là cho header thương lượng nội dung, 409 “Conflict” chủ yếu cho yêu cầu WebDAV, còn 411, 422, 431 cũng là cho các điều kiện cụ thể khác không liên quan ở đây
Lỗi nhóm 300 hay 500 cũng không phù hợp. Đây không phải chuyển hướng hay lỗi phía máy chủ, mà là vấn đề với yêu cầu phía client
Ấm trà hoặc quá dài có vẻ là hai ứng viên tốt nhất
Văn phong của bài này và bài của Chris khiến tôi có cảm giác như việc đưa các tham số truy vấn kiểu này vào là có hại, nhưng tôi không hiểu nó hại ở chỗ nào
Tôi hiểu rằng nó có thể làm hỏng một số URL, và chỉ riêng điều đó cũng đã là lý do đủ để không làm. Nhưng ngoài ra nó có vẻ chỉ là một sự phiền toái nhỏ. Ai giải thích giúp được không?
Từ góc độ thuần kỹ thuật, việc sửa đổi URL là không chính xác về mặt kỹ thuật dù theo tập quán người ta vẫn chấp nhận. Về cơ bản nên coi URL là một giá trị opaque
Từ góc độ xã hội, đó là theo dõi, và các luồng bình luận cùng cấp đã giải thích rất rõ nên tôi không lặp lại
Từ góc độ nhiễu, nó góp phần che khuất những phần người dùng nên quan tâm và làm URL trở nên quá khó, quá phức tạp, đến mức người bình thường không còn để ý đến URL nữa
Refererthì sẽ hiểu vì sao người ta ghét chuyện này: https://en.wikipedia.org/wiki/HTTP_refererCó rất nhiều lý do để bạn không muốn website biết trước khi đến đó bạn đã ở đâu. Về cơ bản là đang chia sẻ lịch sử duyệt web của mình cho trang đang truy cập
Vì vậy header HTTP
Refererđã có rất nhiều cập nhật như giới hạn điều kiện gửi và khả năng tắt hẳn tính năng nàyNếu thêm cùng thông tin đó vào tham số URL thì sẽ lách qua những quy tắc và cơ chế từ chối sẵn có này. Cứ dùng tiêu chuẩn đi
Đây là một thái độ cực đoan đến mức lố bịch, và nó không giải thích được thuyết phục rằng điều này sẽ dẫn đến một web tốt hơn như thế nào
Điểm sau có thể khó hiểu, nhưng với tôi thì tôi hoàn toàn không muốn trong log của mình lưu lại thông tin có thể gây hại cho người dùng
Cá nhân tôi cực ghét khi muốn copy liên kết gửi qua tin nhắn mà lại có đoạn mã theo dõi dài gấp đôi URL gốc gắn kèm. Hoặc tôi phải xóa thủ công từng cái, hoặc để người nhận nhìn một màn hình đầy ký tự ngẫu nhiên rồi tự hỏi đó là cái quái gì
Nó xâm phạm quyền riêng tư của người dùng, trải nghiệm người dùng cũng tệ, và trên hết là chẳng ai yêu cầu điều đó
Vì bài gốc vẫn chưa từng được thảo luận trên HN, tôi đã đặt liên kết đó (https://chrismorgan.info/no-query-strings) ở trên cùng và chuyển liên kết bài phản hồi (https://susam.net/no-query-strings.html) xuống phần mô tả đầu bài
Cả hai đều hay, nhưng ưu tiên bài gốc có vẻ công bằng hơn
Gần đây hầu hết các site vẫn còn dùng GET query quanh đây đều là cổng thu thuế của chính quyền địa phương, cứ chuyền biến qua lại sau khi đăng nhập
Thật ra thứ còn khó chịu hơn nhiều là các parser định tuyến giả vờ như là URL thật trong khi thực chất chỉ làm đúng những gì một yêu cầu GET vốn đã làm
Chuỗi truy vấn có ích. Ví dụ như tìm kiếm file hoặc các loại file động khác, nhưng không nên gắn nó vào các URL không mong đợi truy vấn
Vì vậy tôi nghĩ từ chối các yêu cầu có thêm thứ như UTM là đúng
Nếu chuỗi truy vấn là thứ không được dự kiến mà vẫn xuất hiện, thì 404 có lẽ là phản hồi hợp lý nhất, và 400 cũng có thể phù hợp