議原理到工程實(shí)踐避坑指南)
1. 從一次線上故障說(shuō)起為什么GET請(qǐng)求會(huì)“丟”數(shù)據(jù)去年我負(fù)責(zé)的一個(gè)用戶中心服務(wù)出了個(gè)挺有意思的線上問題。前端同學(xué)在修改用戶昵稱時(shí)為了圖方便直接用了GET請(qǐng)求把新的昵稱拼在URL后面類似/api/user/updateNickname?nickname新名字。上線后風(fēng)平浪靜直到有一天一個(gè)運(yùn)營(yíng)同學(xué)反饋他給一個(gè)VIP用戶設(shè)置的包含特殊符號(hào)和長(zhǎng)文本的昵稱提交后總是失敗但用短一點(diǎn)的英文名就沒事。排查過(guò)程一波三折。一開始懷疑是后端字符編碼問題又或者是接口限流查了半天日志和代碼都沒發(fā)現(xiàn)異常。最后還是運(yùn)維同學(xué)在Nginx的訪問日志里發(fā)現(xiàn)了端倪那條失敗的請(qǐng)求其URL長(zhǎng)度在日志里被截?cái)嗔撕竺娴膮?shù)根本沒傳到后端應(yīng)用。這才恍然大悟問題出在GET請(qǐng)求本身某些代理服務(wù)器或?yàn)g覽器對(duì)URL長(zhǎng)度有隱性的限制超長(zhǎng)的參數(shù)會(huì)被直接截?cái)嗷騺G棄。而POST請(qǐng)求的請(qǐng)求體Body則沒有這個(gè)硬性限制。這個(gè)看似簡(jiǎn)單的“GET和POST區(qū)別”問題實(shí)際上牽扯出的是HTTP協(xié)議設(shè)計(jì)哲學(xué)、瀏覽器實(shí)現(xiàn)、服務(wù)器配置以及安全規(guī)范等一系列深層知識(shí)。很多人包括一些工作幾年的開發(fā)者對(duì)它們的理解可能還停留在“GET取數(shù)據(jù)POST改數(shù)據(jù)”的層面。今天我們就拋開那些教科書式的簡(jiǎn)單對(duì)比從一個(gè)一線開發(fā)者的視角深入聊聊GET和POST那些你必須知道的、真正影響編碼和設(shè)計(jì)的區(qū)別。2. 協(xié)議層面的本質(zhì)差異語(yǔ)義、冪等性與安全性要真正理解GET和POST必須回到HTTP/1.1協(xié)議規(guī)范RFC 7231的定義。這不是死記硬背概念而是理解后續(xù)所有衍生現(xiàn)象和最佳實(shí)踐的基石。2.1 核心語(yǔ)義你究竟想干什么HTTP方法Method的核心是表達(dá)意圖而不僅僅是技術(shù)實(shí)現(xiàn)。GET的語(yǔ)義是“獲取”Fetch。它向服務(wù)器請(qǐng)求一個(gè)指定資源的表示。關(guān)鍵在于GET請(qǐng)求不應(yīng)該改變服務(wù)器的狀態(tài)。你可以把它想象成去圖書館查一本書你告訴管理員書名URL管理員把書資源表示給你。無(wú)論你查多少次圖書館書架上的書服務(wù)器狀態(tài)本身沒有變化。因此GET請(qǐng)求應(yīng)該是安全Safe的。POST的語(yǔ)義是“提交”Submit。它請(qǐng)求服務(wù)器處理請(qǐng)求中包含的實(shí)體通常放在請(qǐng)求體Body中這通常會(huì)導(dǎo)致服務(wù)器狀態(tài)的改變和/或副作用的產(chǎn)生。比如你在圖書館的借閱單請(qǐng)求體上填好信息并提交管理員處理后你的借閱記錄服務(wù)器狀態(tài)就改變了一本書的狀態(tài)也可能從“在館”變?yōu)椤敖璩觥薄K訮OST是非安全的。注意這里的“安全”是協(xié)議術(shù)語(yǔ)特指“是否會(huì)產(chǎn)生副作用”。一個(gè)設(shè)計(jì)良好的GET接口確實(shí)不應(yīng)該修改數(shù)據(jù)庫(kù)但一個(gè)胡亂實(shí)現(xiàn)的GET接口完全可以在后端做刪除操作——這違背了協(xié)議約定會(huì)帶來(lái)嚴(yán)重后果比如網(wǎng)絡(luò)爬蟲可能無(wú)意中觸發(fā)刪除。2.2 冪等性操作一次和操作N次結(jié)果一樣嗎這是面試常考點(diǎn)也是設(shè)計(jì)可靠API的關(guān)鍵。GET是冪等的Idempotent。冪等意味著多次執(zhí)行相同的操作產(chǎn)生的效果與執(zhí)行一次的效果相同。你刷新一個(gè)網(wǎng)頁(yè)GET請(qǐng)求10次服務(wù)器返回的內(nèi)容在資源未更新的情況下和你訪問1次是一樣的服務(wù)器狀態(tài)也不會(huì)因?yàn)槟愕亩啻嗡⑿露淖?0次。這個(gè)特性對(duì)網(wǎng)絡(luò)通信至關(guān)重要它允許客戶端在請(qǐng)求失敗如超時(shí)時(shí)安全地重試而不用擔(dān)心重復(fù)提交。POST是非冪等的。提交一份訂單POST請(qǐng)求一次創(chuàng)建一條訂單記錄。如果因?yàn)榫W(wǎng)絡(luò)超時(shí)客戶端沒收到響應(yīng)而自動(dòng)重試了這個(gè)POST請(qǐng)求服務(wù)器就可能創(chuàng)建出兩條一模一樣的訂單。這就是著名的“重復(fù)提交”問題。因此對(duì)于POST操作服務(wù)端必須設(shè)計(jì)防重機(jī)制如Token、冪等鍵。2.3 可緩存性如何利用這一點(diǎn)提升性能緩存是Web性能優(yōu)化的利器而GET和POST在緩存行為上截然不同。GET請(qǐng)求是可緩存的。因?yàn)樗莾绲惹野踩臑g覽器、CDN、代理服務(wù)器等中間節(jié)點(diǎn)可以大膽地緩存GET請(qǐng)求的響應(yīng)。當(dāng)你再次訪問同一個(gè)URL時(shí)可能直接從本地緩存或就近的CDN節(jié)點(diǎn)獲取數(shù)據(jù)速度極快且減輕了源站壓力。這也是為什么靜態(tài)資源、API查詢接口強(qiáng)烈建議使用GET的原因。POST請(qǐng)求默認(rèn)是不可緩存的。由于它會(huì)導(dǎo)致狀態(tài)變化緩存其響應(yīng)是沒有意義的甚至是有害的想象一下緩存了一個(gè)“支付成功”的頁(yè)面結(jié)果。雖然RFC沒有完全禁止緩存POST響應(yīng)但所有主流瀏覽器和緩存中間件默認(rèn)都不會(huì)緩存它。如果你試圖對(duì)POST接口做緩存優(yōu)化需要非常小心地通過(guò)Cache-Control等頭部顯式控制但這通常不是個(gè)好主意。為了更直觀地對(duì)比我將這些協(xié)議層面的核心區(qū)別整理成了下表特性維度GETPOST對(duì)開發(fā)者的實(shí)際影響語(yǔ)義獲取Fetch資源提交Submit數(shù)據(jù)進(jìn)行處理定義了接口的“用途”是API設(shè)計(jì)的首要依據(jù)。安全性安全不應(yīng)有副作用非安全通常有副作用違反安全性約定如用GET刪除數(shù)據(jù)會(huì)破壞Web基礎(chǔ)設(shè)施如爬蟲、預(yù)取的假設(shè)導(dǎo)致災(zāi)難。冪等性冪等非冪等GET請(qǐng)求失敗可自動(dòng)重試POST請(qǐng)求必須由業(yè)務(wù)邏輯處理防重。可緩存性可緩存瀏覽器、CDN默認(rèn)會(huì)緩存默認(rèn)不可緩存GET接口天然適合做緩存優(yōu)化POST接口的緩存需極其謹(jǐn)慎。請(qǐng)求參數(shù)位置URL的查詢字符串Query String請(qǐng)求體Body決定了參數(shù)是否可見、長(zhǎng)度限制、數(shù)據(jù)類型支持等。數(shù)據(jù)長(zhǎng)度限制受URL長(zhǎng)度限制瀏覽器、服務(wù)器各有不同理論上無(wú)限制受服務(wù)器配置約束GET不適合傳輸大量數(shù)據(jù)如表單提交、文件上傳。數(shù)據(jù)可見性參數(shù)明文顯示在URL、瀏覽器歷史、服務(wù)器日志中參數(shù)在Body中相對(duì)隱蔽但仍為明文GET參數(shù)不適合傳遞敏感信息如密碼、令牌。書簽/分享可被收藏為書簽URL包含完整參數(shù)不可被收藏Body信息不保存在URL中分享一個(gè)搜索結(jié)果GET的鏈接是可行的分享一個(gè)表單提交結(jié)果POST的鏈接則不行。后退/刷新無(wú)害瀏覽器通常會(huì)提示重新提交表單瀏覽器會(huì)提示“確認(rèn)重新提交表單”用戶體驗(yàn)不同POST操作后退刷新需額外處理。3. 實(shí)踐中的關(guān)鍵分野參數(shù)、長(zhǎng)度、安全與瀏覽器行為理解了協(xié)議本質(zhì)我們?cè)倏此鼈冊(cè)诰唧w編碼和運(yùn)行時(shí)的表現(xiàn)。這些是日常開發(fā)中最常碰到的“坑點(diǎn)”。3.1 參數(shù)位置與編碼不僅僅是“放哪兒”那么簡(jiǎn)單GET的參數(shù)通過(guò)URL的**查詢字符串Query String傳遞即?key1value1key2value2的形式。POST的參數(shù)則放在請(qǐng)求體Request Body**中。這個(gè)根本性的區(qū)別導(dǎo)致了連鎖反應(yīng)URL編碼Percent-Encoding由于URL本身是一串特定字符集的文本GET參數(shù)中的特殊字符如空格、中文、、必須進(jìn)行百分號(hào)編碼。例如空格變成%20。如果你在代碼中手動(dòng)拼接GET參數(shù)忘記編碼很可能導(dǎo)致解析錯(cuò)誤。而POST的Body內(nèi)容類型Content-Type為application/x-www-form-urlencoded時(shí)雖然也對(duì)特殊字符進(jìn)行編碼但它是整個(gè)Body作為一個(gè)整體進(jìn)行傳輸編碼邏輯更清晰如果是multipart/form-data或application/json編碼方式又完全不同。數(shù)據(jù)類型支持GET參數(shù)本質(zhì)是文本鍵值對(duì)難以直接傳輸復(fù)雜結(jié)構(gòu)如嵌套JSON或二進(jìn)制數(shù)據(jù)如圖片。雖然可以通過(guò)序列化如JSON序列化成字符串再URL編碼來(lái)傳遞但非常笨拙且受長(zhǎng)度限制。POST的Body則可以輕松支持多種格式表單、JSON、XML甚至二進(jìn)制流這是它成為數(shù)據(jù)提交首選的重要原因。3.2 長(zhǎng)度限制那個(gè)讓我踩坑的“隱形天花板”這是我開篇故障的根本原因。雖然HTTP協(xié)議本身沒有規(guī)定URL的長(zhǎng)度上限但現(xiàn)實(shí)世界中的各個(gè)環(huán)節(jié)都給自己加了限制瀏覽器不同瀏覽器有不同限制。IE早期版本限制約2048字符Chrome、Firefox等現(xiàn)代瀏覽器限制在幾萬(wàn)字符級(jí)別但這只是理論值。服務(wù)器Web服務(wù)器如Nginx、Apache和應(yīng)用程序服務(wù)器如Tomcat都有各自的配置項(xiàng)來(lái)限制請(qǐng)求行包含URL的長(zhǎng)度。例如Nginx的client_header_buffer_size和large_client_header_buffers配置就直接影響能接收的URL長(zhǎng)度。超過(guò)限制服務(wù)器會(huì)直接返回414 URI Too Long或400 Bad Request錯(cuò)誤。代理與CDN中間代理、負(fù)載均衡器、CDN節(jié)點(diǎn)也可能有自身的URL長(zhǎng)度限制并且這個(gè)限制往往不透明最容易在測(cè)試環(huán)境被忽略直到上線后流量經(jīng)過(guò)復(fù)雜網(wǎng)絡(luò)路徑時(shí)才暴露。實(shí)操心得一個(gè)簡(jiǎn)單的經(jīng)驗(yàn)法則是永遠(yuǎn)不要用GET傳遞超過(guò)2000字符的數(shù)據(jù)。對(duì)于需要傳遞大量數(shù)據(jù)的場(chǎng)景如復(fù)雜的查詢條件、長(zhǎng)文本內(nèi)容毫不猶豫地使用POST。在設(shè)計(jì)查詢API時(shí)如果過(guò)濾條件非常復(fù)雜也應(yīng)該考慮使用POST將條件以JSON格式放在Body中這比構(gòu)建一個(gè)超長(zhǎng)的、難以閱讀和維護(hù)的GET URL要優(yōu)雅和可靠得多。3.3 安全與可見性GET參數(shù)是“明信片”GET參數(shù)附在URL上這意味著瀏覽器地址欄可見用戶一眼就能看到不適合傳遞密碼、令牌等敏感信息。瀏覽器歷史記錄URL會(huì)被保存在瀏覽器歷史中別人查看歷史就能看到參數(shù)。服務(wù)器訪問日志W(wǎng)eb服務(wù)器通常會(huì)記錄完整的請(qǐng)求URL到訪問日志文件中。如果日志管理不當(dāng)敏感參數(shù)可能被泄露。Referer頭部當(dāng)從A頁(yè)面跳轉(zhuǎn)到B頁(yè)面時(shí)B頁(yè)面收到的請(qǐng)求中Referer頭部會(huì)包含A頁(yè)面的完整URL。如果A頁(yè)面的URL中含有敏感GET參數(shù)這個(gè)參數(shù)就會(huì)泄露給B頁(yè)面所在的域名。因此任何敏感信息絕對(duì)不要通過(guò)GET傳遞。即使使用HTTPS加密了整個(gè)通信過(guò)程URL中的參數(shù)在客戶端和服務(wù)器端的日志系統(tǒng)中仍然是明文。POST的Body內(nèi)容在HTTPS下是加密的且通常不會(huì)完整記錄到服務(wù)器訪問日志中日志一般只記錄路徑不記錄Body相對(duì)安全。但請(qǐng)注意這并不意味著POST可以隨意傳遞密碼密碼等核心機(jī)密在任何情況下都應(yīng)進(jìn)行哈希加鹽處理后再傳輸。3.4 瀏覽器與用戶的交互行為瀏覽器基于GET和POST的語(yǔ)義差異對(duì)用戶行為有不同的處理刷新與后退刷新一個(gè)GET請(qǐng)求的頁(yè)面瀏覽器會(huì)直接重新發(fā)起請(qǐng)求。刷新或后退到一個(gè)由POST請(qǐng)求產(chǎn)生的頁(yè)面時(shí)幾乎所有瀏覽器都會(huì)彈出提示框詢問用戶“確認(rèn)重新提交表單”。這是因?yàn)闉g覽器知道POST可能改變服務(wù)器狀態(tài)重復(fù)提交可能造成不良后果如重復(fù)扣款。這個(gè)提示是瀏覽器對(duì)用戶的保護(hù)。書簽與鏈接分享GET請(qǐng)求的URL包含了所有參數(shù)因此整個(gè)請(qǐng)求狀態(tài)可以被保存為書簽或通過(guò)鏈接分享。而POST請(qǐng)求的狀態(tài)Body內(nèi)容無(wú)法通過(guò)URL保存因此不能直接書簽或分享。預(yù)取與預(yù)渲染一些瀏覽器或插件會(huì)進(jìn)行預(yù)取Prefetch來(lái)加速瀏覽它們通常只預(yù)取GET請(qǐng)求的鏈接因?yàn)镚ET是安全且冪等的。它們絕不會(huì)去預(yù)取一個(gè)POST鏈接那可能導(dǎo)致未知的副作用。4. 深入技術(shù)細(xì)節(jié)Body、URL與協(xié)議歷史要徹底搞懂我們還得再往下鉆一層看看數(shù)據(jù)到底是怎么“上車”和“下車”的。4.1 GET真的不能有Body嗎這是一個(gè)經(jīng)典的誤解。從HTTP/1.1協(xié)議語(yǔ)法上講GET請(qǐng)求是可以包含消息體Body的。RFC 7231并沒有禁止這一點(diǎn)。然而協(xié)議語(yǔ)義明確指出GET的Body沒有定義任何含義。也就是說(shuō)服務(wù)器可以忽略GET請(qǐng)求中的Body。在實(shí)踐中99.99%的服務(wù)器端框架、庫(kù)、代理和緩存中間件都會(huì)忽略甚至拒絕處理GET請(qǐng)求的Body。例如如果你用curl給一個(gè)Spring Boot的GET接口發(fā)送帶Body的請(qǐng)求Spring默認(rèn)的解析器很可能根本不會(huì)去讀取這個(gè)Body。如果你強(qiáng)行讓服務(wù)端去讀那么你會(huì)破壞所有中間件如緩存服務(wù)器、網(wǎng)關(guān)對(duì)GET請(qǐng)求的假設(shè)導(dǎo)致不可預(yù)知的行為。結(jié)論在工程實(shí)踐上必須視“GET請(qǐng)求沒有Body”為鐵律。任何需要傳遞到服務(wù)端的數(shù)據(jù)都必須通過(guò)URL的路徑Path或查詢字符串Query String來(lái)傳遞。4.2 POST的參數(shù)可以放在URL里嗎反過(guò)來(lái)POST請(qǐng)求當(dāng)然可以把參數(shù)放在URL的查詢字符串中。這在一些特定場(chǎng)景下是合理的例如分頁(yè)或過(guò)濾參數(shù)POST /api/users/search?page1size20將分頁(yè)、排序等控制參數(shù)放在URL中而將復(fù)雜的查詢條件如一個(gè)多字段的過(guò)濾對(duì)象放在Body的JSON里。這樣設(shè)計(jì)URL部分代表了“查詢的視圖”Body部分代表了“查詢的具體內(nèi)容”語(yǔ)義清晰。API版本號(hào)或訪問令牌有時(shí)會(huì)將API版本/v1/或認(rèn)證令牌?access_tokenxxx放在URL中而將業(yè)務(wù)數(shù)據(jù)放在Body里。但需要注意的是放在URL中的參數(shù)同樣會(huì)受到長(zhǎng)度限制和可見性問題的約束。4.3 一個(gè)歷史“包袱”POST的兩種編碼早期Web以表單提交為主POST請(qǐng)求體主要有兩種編碼方式理解它們有助于處理一些遺留系統(tǒng)或特定場(chǎng)景application/x-www-form-urlencoded這是默認(rèn)的表單編碼方式。它會(huì)將Body中的鍵值對(duì)如name張三age20進(jìn)行URL編碼空格變號(hào)特殊字符百分號(hào)編碼格式和GET的查詢字符串非常像但位置在Body里。這種格式簡(jiǎn)單但不適合傳輸二進(jìn)制文件。multipart/form-data當(dāng)表單需要上傳文件時(shí)必須使用這種編碼。它會(huì)將整個(gè)Body分割成多個(gè)部分Part每個(gè)部分對(duì)應(yīng)一個(gè)表單字段并包含自己的頭部信息如Content-Type。這種方式可以高效地混合傳輸文本和二進(jìn)制數(shù)據(jù)但格式復(fù)雜解析起來(lái)也比上一種麻煩。現(xiàn)代前端開發(fā)中使用fetch或axios等庫(kù)我們更常用application/json格式來(lái)傳遞復(fù)雜的結(jié)構(gòu)化數(shù)據(jù)后端框架也能很好地支持解析。這已經(jīng)成為RESTful API設(shè)計(jì)的事實(shí)標(biāo)準(zhǔn)。5. 設(shè)計(jì)抉擇與最佳實(shí)踐什么時(shí)候該用誰(shuí)理論說(shuō)了一大堆最終要落到代碼和設(shè)計(jì)上。下面是我總結(jié)的一些核心原則和場(chǎng)景分析。5.1 首要原則遵從語(yǔ)義Semantic這是最高原則。選擇GET還是POST首先取決于你的操作意圖而不是技術(shù)實(shí)現(xiàn)的難易。意圖是查詢、獲取數(shù)據(jù)且操作不應(yīng)改變服務(wù)器狀態(tài) -用GET。例子搜索商品、獲取用戶信息、查詢訂單列表、下載文件。意圖是創(chuàng)建、更新、刪除數(shù)據(jù)或觸發(fā)一個(gè)有副作用的操作 -用POST或PUT、DELETE但POST是通用性最強(qiáng)的。例子用戶注冊(cè)創(chuàng)建、修改密碼更新、提交訂單創(chuàng)建并觸發(fā)庫(kù)存變更等副作用。違反語(yǔ)義的后果很嚴(yán)重。用GET來(lái)刪除資源可能導(dǎo)致搜索引擎爬蟲、瀏覽器預(yù)加載、鏈路監(jiān)控系統(tǒng)等無(wú)意中觸發(fā)刪除操作。用POST來(lái)做一個(gè)純查詢你就放棄了緩存帶來(lái)的巨大性能優(yōu)勢(shì)并且讓用戶無(wú)法收藏或分享這個(gè)查詢結(jié)果的鏈接。5.2 場(chǎng)景化決策指南場(chǎng)景推薦方法理由與注意事項(xiàng)簡(jiǎn)單數(shù)據(jù)查詢?nèi)绺鶕?jù)ID查詳情GET冪等、安全、可緩存。URL簡(jiǎn)潔易于分享和書簽。復(fù)雜條件查詢?nèi)绨鄠€(gè)過(guò)濾、排序字段POST查詢條件可能很長(zhǎng)或結(jié)構(gòu)復(fù)雜放在JSON Body中更靈活不受URL長(zhǎng)度限制也便于前端構(gòu)造和后端解析。創(chuàng)建新資源如發(fā)表文章POST非冪等操作必須用POST或PUT if you have the full URI。更新資源如修改文章標(biāo)題PUT/PATCH更符合RESTful語(yǔ)義。如果只用POST也務(wù)必在Body中指明操作類型。刪除資源DELETE語(yǔ)義最清晰。用POST包裹刪除動(dòng)作也是常見做法尤其是前端表單限制時(shí)。提交表單數(shù)據(jù)含文件上傳POST數(shù)據(jù)量大可能含二進(jìn)制必須用POST。編碼用multipart/form-data。觸發(fā)一個(gè)無(wú)返回值的動(dòng)作如“發(fā)送驗(yàn)證碼”、“清理緩存”POST這是一個(gè)有副作用的操作非冪等應(yīng)用POST。需要被收藏或分享的頁(yè)面如一個(gè)特定的搜索結(jié)果頁(yè)GET狀態(tài)參數(shù)保存在URL中才能實(shí)現(xiàn)鏈接分享。如果參數(shù)復(fù)雜可考慮生成一個(gè)唯一短鏈通過(guò)GET短鏈映射到服務(wù)器端存儲(chǔ)的復(fù)雜查詢條件。涉及敏感信息密碼、支付令牌POST(且必須HTTPS)絕對(duì)不要出現(xiàn)在URL、日志中。POST Body在HTTPS下加密傳輸。服務(wù)端日志不應(yīng)記錄Body。5.3 關(guān)于RESTful API設(shè)計(jì)的特別說(shuō)明在RESTful架構(gòu)風(fēng)格中HTTP方法被賦予了更精確的語(yǔ)義GET獲取資源。POST創(chuàng)建資源服務(wù)端決定URI。PUT更新資源客戶端提供完整資源及URI。PATCH部分更新資源。DELETE刪除資源。在這種情況下POST和GET的界限更加清晰。但即使在RESTful API中對(duì)于復(fù)雜的、只讀的查詢操作例如一個(gè)包含多重聚合、過(guò)濾的報(bào)表查詢使用POST來(lái)傳遞查詢條件也是被廣泛接受的這被稱為“Query by POST”它避免了構(gòu)造一個(gè)極其冗長(zhǎng)且可能超出限制的GET URL。5.4 一個(gè)真實(shí)的架構(gòu)案例搜索API的演進(jìn)我經(jīng)歷過(guò)一個(gè)電商搜索系統(tǒng)的重構(gòu)。最初搜索接口是GET參數(shù)全部堆在URL里/search?kw手機(jī)category123price_min1000price_max5000sortsalespage1...。隨著業(yè)務(wù)復(fù)雜篩選條件增加到幾十個(gè)品牌、屬性、服務(wù)承諾等URL經(jīng)常超長(zhǎng)前端拼接麻煩后端解析也容易出錯(cuò)。重構(gòu)后我們將其改為POST /search。請(qǐng)求體是一個(gè)結(jié)構(gòu)清晰的JSON{ keyword: 手機(jī), filters: { categoryId: 123, priceRange: {min: 1000, max: 5000}, brandIds: [101, 102], attributes: [{key: color, value: black}] }, sort: {field: sales, order: desc}, page: 1, size: 20 }這樣做帶來(lái)了幾個(gè)好處徹底擺脫長(zhǎng)度限制無(wú)論條件多復(fù)雜JSON結(jié)構(gòu)都能輕松容納。前后端協(xié)作更高效JSON Schema可以明確定義接口格式前后端調(diào)試方便。易于擴(kuò)展新增篩選條件只需在JSON中添加字段無(wú)需改動(dòng)URL結(jié)構(gòu)。緩存策略調(diào)整由于改為POST默認(rèn)不可緩存。我們針對(duì)這個(gè)高頻接口在網(wǎng)關(guān)層設(shè)計(jì)了基于請(qǐng)求體摘要如MD5的緩存機(jī)制將計(jì)算出的摘要值作為緩存鍵同樣獲得了緩存性能提升只是實(shí)現(xiàn)上比GET復(fù)雜一些。這個(gè)案例說(shuō)明規(guī)則是死的人是活的。在深刻理解GET和POST本質(zhì)區(qū)別的基礎(chǔ)上結(jié)合具體業(yè)務(wù)場(chǎng)景和約束如性能、復(fù)雜度做出最合理的設(shè)計(jì)選擇這才是資深工程師的價(jià)值所在。