ผมสั่งแบน Query String ไปแล้ว
(chrismorgan.info)- Chris Morgan ตัดสินใจบล็อก query string ที่ไม่ได้รับอนุญาต ทั้งหมดบนเว็บไซต์ของเขา โดยตอนนี้ได้ทำไว้ใน Caddyfile แล้ว
- เขาไม่ต้องการให้มีการต่อพารามิเตอร์สำหรับติดตามอย่าง
?ref=example.comเข้ากับ URL และมองว่าถ้าจำเป็นก็ไปดูที่เฮดเดอร์ Referer ได้ - เขามองว่า UTM parameters อย่าง
?utm_source=example&utm_*&c.*เป็นสิ่งที่เจ้าของเว็บไซต์ใช้เอง ไม่ใช่สิ่งที่คนนอกควรเอามาต่อเพิ่ม - ตอนนี้เว็บไซต์นี้ไม่ได้ใช้ query string เลย และถ้าในอนาคตจะใช้ ก็มีแผนจะอนุญาตเฉพาะ พารามิเตอร์ที่รู้จักเท่านั้น
- URL สุดท้ายถูกกำหนดเป็น
/no-query-stringsและไม่ได้เลือก/%3Fเพราะมีปัญหากับการ rewrite ของtry_filesใน Caddy
บล็อก query string ที่ไม่ได้รับอนุญาต
- Chris Morgan ตัดสินใจบล็อก query string ที่ไม่ได้รับอนุญาต ทั้งหมดบนเว็บไซต์ของเขา
- เขาไม่ต้องการให้มีการต่อพารามิเตอร์สำหรับติดตามอย่าง
?ref=example.comเข้ากับ URL ของตัวเอง และมองว่าถ้าจำเป็นก็ไปดูที่เฮดเดอร์Refererได้ - เขามองว่า UTM parameters อย่าง
?utm_source=example&utm_*&c.*เป็นสิ่งที่เจ้าของเว็บไซต์ใช้เอง ไม่ใช่สิ่งที่คนนอกควรเอามาต่อเพิ่ม - ตอนนี้เว็บไซต์นี้ไม่ได้ใช้ query string เลย และถ้าในอนาคตจะใช้ ก็มีแผนจะอนุญาตเฉพาะ พารามิเตอร์ที่รู้จักเท่านั้น
- ในอดีตเขาเคยใช้ URL สำหรับทำ cache invalidation ของสไตล์ชีตในรูปแบบ
?t=…,?h=…แต่ก็มองว่าถ้าคำขอแบบนั้นพังไปก็ไม่เป็นไร - การบล็อกนี้ตอนนี้ถูกนำไปใช้ใน Caddyfile แล้ว
กระบวนการเลือก URL
-
แผนที่จะใช้
/?- ตอนแรกเขาอยากเผยแพร่หน้านี้ที่
https://chrismorgan.info/?มาก - เพราะมันเป็นรูปแบบที่มี path ว่างและ query ว่าง ซึ่งพบได้ทั่วไป แต่สามารถทำลายสมมติฐานที่ผิดพลาดอยู่หลายอย่าง และอาจทำให้บางเครื่องมือไปต่อไม่ถูก
- ดูเหมือนว่า
curlจะตัดเครื่องหมายคำถามท้ายสุดทิ้งอย่างไม่เหมาะสมบนบรรทัดคำสั่ง ส่วนการใช้งานผ่านไลบรารีเขายังไม่ได้ทดสอบ - สุดท้ายเขาเลือกเคารพแนวคิดเรื่อง path และใจดีกับผู้ใช้เครื่องมือมากขึ้น โดยเฉพาะเมื่อมองว่าเขาได้ฝืน Caddy ไปในทางที่ชวนลำบากพอแล้ว
- ตอนแรกเขาอยากเผยแพร่หน้านี้ที่
-
แผนที่จะใช้
/%3F- แผนถัดมาคือเผยแพร่ที่
/%3Fซึ่งเป็น path ที่มีค่าเป็น?และไม่มี query - แต่พบว่ามีปัญหาที่ Caddy ไม่สามารถจัดการได้เมื่อเกี่ยวข้องกับการ rewrite ของ
try_files - อีชชูที่เกี่ยวข้องคือ
try_filesทำ path ที่มีอักขระอย่าง?และ%พัง
- แผนถัดมาคือเผยแพร่ที่
-
ตัวเลือกสุดท้าย
- URL สุดท้ายถูกกำหนดเป็น
/no-query-strings /?หรือ/%3Fอาจถูกนำไปใช้ในภายหลังสำหรับจุดประสงค์อื่นที่เกี่ยวกับ query string
- URL สุดท้ายถูกกำหนดเป็น
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ฉันสงสัยเรื่องนี้เลยกลับไปดูมาตรฐาน W3C ของ HTML และ URL อีกครั้ง แล้วก็พบว่าน่าแปลกทีเดียวว่ารูปแบบของ query string นั้นไม่ได้มีการนิยามอะไรไว้เป็นพิเศษนอกจาก percent-encoding
เราอาจสับสน query string กับ query string แบบ “form-urlencoded”[0] ได้ แต่จริง ๆ แล้วนั่นเป็นเพียงหนึ่งในรูปแบบที่ทำงานร่วมกันได้เท่านั้น โดยทั่วไป query string คือสตริง percent-encoded ตามอำเภอใจที่อยู่หลัง
?ของ URL[1] และเป็นอีกหนึ่งพร็อพเพอร์ตีของอ็อบเจ็กต์URLใน HTML ที่สามารถนำไปใช้สร้าง response ได้อ็อบเจ็กต์
URLSearchParamsคือผลลัพธ์จากการพาร์ส query string ด้วยตัวพาร์สแบบ form-urlencoded แต่นั่นเป็นเพียงชั้นเพื่อการทำงานร่วมกันสำหรับ JavaScript เท่านั้นพูดตามตรง ก่อนจะไปดูมาตรฐานฉันเตรียมจะโต้แย้งไว้แล้ว แต่ตัวมาตรฐานค่อนข้างชัดเจน การตอบกลับด้วย 404 ต่อ query string ที่ไม่คาดคิดก็อาจเหมาะสมได้ query string เป็นส่วนหนึ่งของ URL API พอ ๆ กับ path และคนส่วนใหญ่น่าจะยอมรับได้ว่าการเอาสตริงตามอำเภอใจไปต่อท้าย path นั้นไม่ดีและเป็นพฤติกรรมที่ไม่ได้ถูกนิยามไว้
[0]: https://url.spec.whatwg.org/#application/x-www-form-urlencod...
[1]: https://url.spec.whatwg.org/#url-class
index.phpไฟล์เดียว แล้วจัดการ routing ทั้งหมดด้วย query stringแน่นอนว่าใช้รูปแบบ form-urlencoded และคนก็ไม่ได้เถื่อนกันขนาดนั้น จึงมี URL อย่าง
index.php?p=home,index.php?p=shopหรือindex.php?action=showthread&forum=42&thread=17976โผล่มา ในโครงสร้างแบบนี้จะเห็นได้ชัดทันทีว่า 404 คือคำตอบที่ถูกต้องสำหรับ query parameter ที่ไม่รู้จักที่จริงทุกวันนี้ก็ยังมีหลายเว็บทำแบบนั้นอยู่ เพียงแค่ซ่อนไว้หลัง rewrite rule ของ Apache/nginx ไม่กี่บรรทัดเพราะเรื่อง SEO
ท้ายที่สุดแล้ว URL ก็เป็นเพียง สตริง ที่เซิร์ฟเวอร์เป็นคนตัดสินใจว่าจะจัดการอย่างไร
สิ่งที่ตลกมากในประเด็นนี้คือ คนกังวลผลข้างเคียงของการตอบ 404 แต่กลับลืมไปสนิทว่าตลอดประวัติศาสตร์เว็บ path เคยไร้ความหมายมานานแค่ไหน ตอนนี้ path ชนะแล้ว ทุกวันนี้แทบไม่มีใครเริ่มต้นใหม่ด้วย URL แบบ
/item?id=…แล้ว ดีเลย!มันอ่านได้ประมาณว่า “แก้คำขอแล้วลองใหม่” และฉันก็ใช้แบบนั้นใน API ที่ให้บริการอยู่ด้วย เหตุผลที่ชอบอันนี้มากกว่า 406 ก็เพราะมันไม่ใช่ปัญหาที่ฝั่งฉันจัดการไม่ได้ ถ้าคุณพยายามทำให้พังด้วยการเติมอะไรลงใน query string หรือไม่ได้สร้าง request ตามเอกสาร นั่นเป็นความรับผิดชอบของผู้ร้องขอ
https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/...
ตัวอย่างเช่นในมุมของ cache อาจถือว่า
url?a=b&c=dตรงกับurl?c=d&a=bมีธรรมเนียมจำนวนมากที่ไม่เคยถูกบันทึกเป็นมาตรฐานอย่างเป็นทางการ แต่ถ้าไม่ทำตามก็พังในวงกว้าง และก็มี “มาตรฐาน” อีกมากที่ถ้าทำตามตัวอักษรเป๊ะ ๆ จะกลายเป็นคนโง่
ในกรณีของบทความต้นฉบับ สิ่งที่พังคือคนที่พยายามเข้าเว็บนั้น และส่วนใหญ่ก็คงกดปุ่มย้อนกลับในเบราว์เซอร์แล้วไปทำอย่างอื่นต่อ จะยอมรับความเสียหายระดับนั้นไหมก็เป็นเรื่องที่เจ้าตัวตัดสินใจได้ แต่การที่มาตรฐานไม่ได้ห้ามไว้ ไม่ได้แปลว่ามันได้รับอนุญาตโดยนิยาม และในทางกลับกัน ต่อให้มาตรฐานห้ามไว้ ก็ไม่ได้ทำให้กลายเป็นสิ่งต้องห้ามขึ้นมาทันที
เท่าที่ฉันเข้าใจคือเขาน่าจะรำคาญที่เว็บอื่นใส่ query string อย่าง
?ref=origin.comต่อท้ายลิงก์ที่ชี้มายังเว็บไซต์ของผู้เขียนฉันไม่เข้าใจว่ามันให้ประโยชน์อะไรกับเว็บไซต์ต้นทาง และสร้างความเสียหายอะไรกับเว็บไซต์ของผู้เขียน
พฤติกรรมของทั้งสองฝั่งดูสับสนไปหมด
ฉันพอเข้าใจเวลาเรารันแคมเปญโฆษณาแล้ว Google ใส่ UTM query string เพื่อจะติดตามว่าผู้ใช้มาจากแคมเปญไหน เพราะตอนนั้นต้นทางกับปลายทางร่วมมือกันอยู่ แต่กรณีนี้ฝั่งต้นทางกลับใส่อะไรเพิ่มมาโดยไม่มีเหตุผล ทำไมกัน?
refว่ามีทราฟฟิกจำนวนมากมาจากxyz.comแล้วอาจคิดจะไปลงโฆษณาหรือทำพาร์ตเนอร์กับเว็บนั้นพูดตรง ๆ ว่ามันมีประโยชน์มากกับเว็บเฉพาะทาง/สตาร์ตอัป ฉันเคยอยู่ทั้งสองฝั่งของบทสนทนาที่เริ่มต้นจากการเห็นค่าพวกนี้ในเว็บ analytics ครั้งหนึ่งฉันเป็นฝ่ายติดต่อไปเพราะเห็นทราฟฟิกที่เข้ามา อีกครั้งหนึ่งเป็นเว็บที่ฉันลิงก์ไปติดต่อกลับมา และทั้งสองครั้งก็จบลงด้วยพาร์ตเนอร์ชิปที่เป็นประโยชน์ต่อทั้งคู่
ฉันก็พอเข้าใจประเด็นเรื่องความเป็นส่วนตัวอยู่บ้าง แต่จริง ๆ แล้วมันไม่ได้ให้ข้อมูลมากไปกว่า header มาตรฐาน
Refererเลย แค่ถ้าใช้เครื่องมือวิเคราะห์อย่าง Simple Analytics/Plausible มันจะมองเห็นได้ชัดกว่ามากการเติม query string มักถูกใช้เพื่อการติดตาม แค่ดูจากการมีฟีเจอร์อย่าง “copy clean link” ของ Firefox หรือ Enhanced Tracking Protection ที่ลบ UTM parameter บางตัวออกล่วงหน้า ก็เห็นได้แล้วว่ามีคนจำนวนมากไม่ต้องการสิ่งนี้
บางเว็บไซต์ยินดีเข้าร่วมระบบที่ฉันเรียกคร่าว ๆ ว่า “เศรษฐกิจการติดตาม” เพราะผู้รับสามารถดูจาก log ได้ว่ามีคนจำนวนมากมาจากเว็บไซต์ของตน และอาจทำสิ่งที่เป็นประโยชน์ต่อเว็บนั้น
การปฏิเสธ query string ก็เป็นการประท้วงระบบนี้แบบเรียบง่าย
จากคำอธิบายว่าเป็น “เว็บคอนโซลขนาดเล็ก กระจายศูนย์ และโฮสต์เอง ที่ช่วยให้ผู้เยี่ยมชมเว็บไซต์สามารถสำรวจเว็บไซต์และหน้าที่น่าสนใจซึ่งแนะนำโดยชุมชนผู้ดูแลเว็บไซต์ส่วนตัวอิสระ” ทำให้ฉันนึกได้ว่าเมื่อก่อนเราเรียกสิ่งนี้ว่า Webring แค่ไม่ได้หรูหราขนาดนี้
ปัญหาอย่างหนึ่งที่ฉันเคยเจอตอนพัฒนาเฟรมเวิร์กแอปพลิเคชันโอเพนซอร์สคือ โฮสติ้งที่ใช้ FastCGI ไม่เคารพ header
Authทำให้ต้องส่งโทเค็นผ่าน query แทน เวลาคัดลอก/วางเว็บแอดเดรสแล้วโทเค็นติดไปด้วยมันแย่มาก ตอนนี้อาจถูกแก้ไปแล้วก็ได้สำหรับ backend ที่ฉันควบคุมเองและไม่จำเป็นต้องเปิดให้ทุกคนใช้ ฉันใช้ header
Authพังใช่ไหม?ฉันสงสัยว่าคุณช่วยอธิบายส่วนนี้เพิ่มได้ไหม ในทางเทคนิคฟังดูเหมือนกำลังบอกว่าเรคอร์ด
PARAMไม่ได้ส่งค่าตามที่คาดไว้จริง ๆเขาบอกว่า “ดังนั้นฉันจึงลองใช้ข้อห้ามแบบครอบจักรวาลกับเว็บไซต์นี้: ไม่อนุญาต query string ที่ไม่ได้รับอนุมัติ” แต่ดูเหมือนเว็บไซต์ของเขาจะส่ง 414 กลับมาเมื่อ request มี query string ซึ่งฉันคิดว่าเป็นตัวเลือกที่ผิด
ถ้าการประท้วงนี้ตั้งใจจะปกป้องผู้ใช้ แล้วทำไมถึงลงโทษผู้ใช้ที่แต่แรกก็อาจควบคุมสตริงนั้นไม่ได้?
สู้ใช้มันเป็นสัญญาณเพื่อบอกวิธีให้ผู้ใช้ตัดสินใจเรื่องนี้ด้วยตัวเองผ่านเครื่องมือในเบราว์เซอร์หรือวิธีอื่นจะไม่ดีกว่าหรือ?
400 Bad Request เป็นรหัส client error ทั่วไปที่ถูกต้อง แต่ไม่สนุก
402 Payment Required บอกตามตรงว่าถ้าคุณจ่ายเงินเพื่อขอให้ URL บางอันที่มี query string ใช้งานได้ ฉันก็เปิดรับนะ
404 Not Found แต่ก็มีโอกาสเกิดผลข้างเคียงได้ง่ายเกินไป และไม่สื่ออารมณ์ว่า ‘รูปแบบของ request ผิด’ อย่างที่ฉันต้องการ
303 See Other โดยไม่มี header
Locationเดี๋ยวนี้แทบไม่เห็นแล้ว แต่ก็ชอบธรรม อย่างน้อยใน RFC 2616 เป็นเช่นนั้น (“The different URI SHOULD be given by the Location field in the response”). แต่ใน 7231 และ 9110 มันเปลี่ยนไปเป็นการเขียนที่ตั้งอยู่บนสมมติฐานว่ามี headerLocationอยู่ (“… as indicated by a URI in the Location header field”). ในขณะที่ 301, 302, 307, 308 ระบุว่า “the server SHOULD generate a Location header field”. เอาเป็นว่า See Other ที่ไม่มี headerLocationฉันก็ยังมองว่าโอเคพอสมควร แต่ URI Too Long มันตลกกว่า”https://chrismorgan.info/no-query-strings?foo
ตรงที่เขาเขียนว่า “คุณอาจบอกว่าฉันกำลังใช้ 414 URI Too Long อย่างผิดวัตถุประสงค์ คำตอบของฉันคือ วิธีนี้มันตลกกว่า ทางเลือกอื่นที่ฉันเคยพิจารณามีดังนี้…” ฉันคิดว่าอีกตัวเลือกหนึ่งคือ 418 I'm a teapot เพราะปกติแล้วกาน้ำชาก็ไม่รองรับ query string เหมือนกัน
มีหลายตัวเลือกที่ดูเหมาะแต่พอมองละเอียดแล้วไม่ใช่ เช่น 406 “Not Acceptable” เป็นเรื่องของ header สำหรับ content negotiation, 409 “Conflict” มักใช้กับคำขอ WebDAV และ 411, 422, 431 ก็เป็นเงื่อนไขเฉพาะที่ไม่เกี่ยวกับกรณีนี้
error ระดับ 300 หรือ 500 ก็ไม่เหมาะ เพราะนี่ไม่ใช่เรื่องการย้ายเส้นทางหรือความล้มเหลวฝั่งเซิร์ฟเวอร์ แต่เป็นปัญหาของ request ฝั่งไคลเอนต์
ดังนั้นกาน้ำชาหรือยาวเกินไปก็ดูเป็นตัวเต็งที่สุด
จากน้ำเสียงของบทความนี้และบทความของ Chris เหมือนการใส่ query parameter แบบนี้เป็นเรื่องอันตราย แต่ฉันไม่เข้าใจว่ามันอันตรายอย่างไร
ฉันเข้าใจว่ามันอาจทำให้ URL บางอันพังได้ และแค่นั้นก็น่าจะเป็นเหตุผลเพียงพอที่จะไม่ทำอยู่แล้ว แต่ก็ดูเหมือนเป็นความไม่สะดวกเล็กน้อย ใครอธิบายให้หน่อยได้ไหม?
จากมุมมองของความบริสุทธิ์ทางเทคนิค แม้จะยอมรับกันตามธรรมเนียม การไปแก้ URL ก็ยังไม่ถูกต้องในเชิงเทคนิค URL ควรถูกปฏิบัติเป็น ค่าทึบแสง โดยพื้นฐาน
จากมุมมองทางสังคม มันคือการติดตาม ซึ่งในเธรดความเห็นข้างเคียงก็อธิบายไว้ดีแล้ว ฉันจะไม่พูดซ้ำ
จากมุมมองเรื่องสัญญาณรบกวน มันทำให้สิ่งที่ผู้ใช้ควรสนใจถูกกลบ และทำให้ URL ยากและซับซ้อนเกินไป จนคนทั่วไปเลิกสนใจ URL ไปเลย
Refererจะเข้าใจว่าทำไมคนถึงไม่ชอบ: https://en.wikipedia.org/wiki/HTTP_refererมีหลายเหตุผลที่คุณอาจไม่อยากให้เว็บไซต์ปลายทางรู้ว่าก่อนหน้านี้คุณอยู่ที่ไหน โดยพื้นฐานแล้วมันคือการแชร์ ประวัติการท่องเว็บ ให้กับเว็บไซต์ที่คุณกำลังเข้าชม
เพราะแบบนี้ header HTTP
Refererจึงมีการอัปเดตมากมาย ทั้งข้อจำกัดด้านเงื่อนไขการส่งและความสามารถในการปิดฟีเจอร์นี้ไปเลยถ้าเพิ่มข้อมูลเดียวกันลงใน URL parameter ก็เท่ากับเป็นการเลี่ยงกฎและความสามารถในการปฏิเสธที่มีอยู่เดิมเหล่านี้ ใช้มาตรฐานไปเลยดีกว่า
นี่เป็นท่าทีที่สุดโต่งเกินเหตุ และไม่ได้อธิบายอย่างเหมาะสมเลยว่ามันจะนำไปสู่เว็บที่ดีกว่าได้อย่างไร
อย่างหลังอาจเข้าใจยากหน่อย แต่สำหรับฉัน ฉันไม่อยากให้มีข้อมูลที่อาจทำอันตรายต่อผู้ใช้ถูกบันทึกอยู่ใน log เด็ดขาด
ในทางส่วนตัว ฉันเกลียดมากเวลาจะคัดลอกลิงก์ไปส่งในข้อความแล้วมี tracking code ที่ยาวเป็นสองเท่าของ URL ต้นฉบับติดมาด้วย ต้องมานั่งลบทิ้งทีละตัว หรือไม่ก็ปล่อยให้คนรับเห็นตัวอักษรสุ่มเต็มหน้าจอแล้วงงว่านี่มันอะไร
มันละเมิดความเป็นส่วนตัวของผู้ใช้ ประสบการณ์ใช้งานก็แย่ และที่สำคัญที่สุดคือไม่มีใครร้องขอสิ่งนี้เลย
เนื่องจากต้นฉบับยังไม่เคยถูกพูดถึงบน HN มาก่อน ฉันจึงเอาลิงก์นั้น (https://chrismorgan.info/no-query-strings) ไว้บนสุด และย้ายลิงก์บทความตอบกลับ (https://susam.net/no-query-strings.html) ไปไว้ในคำอธิบายด้านบน
ทั้งสองบทความก็ดี แต่ดูยุติธรรมกว่าที่จะให้ความสำคัญกับต้นฉบับก่อน
แถวนี้เว็บไซต์ส่วนใหญ่ที่ยังใช้ GET query กันอยู่คือ เว็บไซต์เก็บภาษี ของหน่วยงานท้องถิ่น ซึ่งจะส่งตัวแปรไปมาหลังจากล็อกอิน
จริง ๆ แล้วสิ่งที่น่ารำคาญกว่ามากคือ routing parser ที่ทำงานเหมือนกับ GET request ทุกอย่าง แต่แกล้งทำเป็นว่าเป็น URL จริง
query string มีประโยชน์ เช่น ใช้กับการค้นหาไฟล์หรือไฟล์ไดนามิกประเภทอื่น ๆ แต่ไม่ควรเอาไปต่อท้าย URL ที่ไม่ได้คาดว่าจะมี query string
เพราะอย่างนั้นฉันจึงคิดว่าการปฏิเสธ request ที่มีอะไรอย่าง UTM แถมมาด้วยก็ถูกต้องแล้ว
ถ้าไม่ได้คาดว่าจะมี query string แต่กลับมีเข้ามา 404 ดูจะสมเหตุสมผลที่สุด และ 400 ก็อาจเหมาะสมได้เช่นกัน