今天做網站【標簽】篩選功能時,出現了這么個奇葩的問題。
我是直接通過<a>標簽中href來跳轉的,url中包含漢字
<a href="/tags/標簽A">標簽A</a>
后台代碼是這樣的:
@RequestMapping(value = "/tags/{tagname}") public String tags(@PathVariable String tagname) {
// ISO-8859-1 ==> UTF-8 進行編碼轉換
tagname = encode_to_utf8(tagname);
// 其余處理略
}
按理說這樣就行了,各大瀏覽器也正常執行了。
但是,一不下心發現,只要URL中出現“充”這個漢字,直接就報404錯誤
例如這樣:
<a href="/tags/標簽充A">標簽充A</a>
奇葩吧。
經過漫長的調查發現,原因有可能是:
充這個漢字在URL中直接提交,經過瀏覽器轉碼后,會變成一串包含“/”的“亂碼”。
后來經過類似測試發現,果然只要URL中包含“/”的參數,都無法通過@PathVariable正確匹配。
有人說不如改成這樣:
方案1:
在Server端通過urlencode把漢字先進行UTF-8編碼,然后扔到前端。
否決:這樣做的話,URL就會變成這個丑樣,這和亂碼有什么區別?真心不喜歡。
<a href="/tags/%D6%D0%B9%FA">標簽充A</a>
后來縱觀各大站點,各有各的做法
方案2:
<a href="/tags?tagname=標簽充A">標簽充A</a>
然后在Controller中用@RequestParam來接收參數,這樣確實是可以的。
否決:但是SEO大神說,url中包含?的動態參數后,有可能會被蜘蛛重復抓取,不利於SEO。
方案3 :把漢字便簽轉換成拼音
<a href="/tags/biaoqianchongA">標簽充A</a>
否決:這樣可以是可以,但是還要在搞一個漢字轉拼音插件,而且看上去也不直觀,不好。
方案4:給標簽一個ID
<a href="/tags/T1">標簽充A</a>
否決:這樣可以是可以,但是我還要該表結構,蛋疼。
方案5:用JS阻斷A的href,實現POST跳轉
否決:現在百度已經可以解析JS了嗎?
大家還有別的方案沒有??
難道就沒有辦法在保持URL格式與漢字都不變的情況,實現這個功能嗎?
最后終於發現,有人這樣搞定了!
前端:
<a href="/tags/標簽充A">標簽充A</a>
后端:
@RequestMapping(value = "/tags/**") public String tags(HttpServletRequest request) { // ISO-8859-1 ==> UTF-8 進行編碼轉換 String tagname = extractPathFromPattern(request); tagname = ToolUtils.encodeStr(tagname); // 其余處理略 } // 把指定URL后的字符串全部截斷當成參數 // 這么做是為了防止URL中包含中文或者特殊字符(/等)時,匹配不了的問題 private static String extractPathFromPattern( final HttpServletRequest request) { String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE); return new AntPathMatcher().extractPathWithinPattern(bestMatchPattern, path); }
搞完之后,不管你輸入什么樣的URL,都能進入到指定的方法!
<a href="/tags/標簽充A">標簽充A</a>
<a href="/tags/標簽充A/asd/asd">標簽充A</a>
<a href="/tags/標簽充A/BB/cc.html">標簽充A</a>
參考原文地址:http://kamatama41.hatenablog.com/entry/20130411/1365668200