Spring MVC で日本語を含むURLにリダイレクトすると…
@GetMapping(path = "bar") String somePage() { return "redirect:/to/日本語url"; }
$ curl -v http://localhost:8080/foo/bar * Trying ::1... * TCP_NODELAY set * Connected to localhost (::1) port 8080 (#0) > GET /it/japanese HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.54.0 > Accept: */* > < HTTP/1.1 302 < Location: http://localhost:8080/to/???url < Content-Language: ja-JP < Content-Length: 0 < Date: Wed, 03 Jan 2018 17:03:47 GMT < * Connection #0 to host localhost left intact
日本語urlにリダイレクトされてほしいけど、日本語がURLエンコーディングされてなくて残念なやつ。
ちょっと調べたのでメモ。
仕組み
ViewResolver
(実装はUrlBasedViewResolver
/AbstractCachingViewResolver
) のresolveViewName
からcreateView
を経てRedirectView
に解決される。- 解決された
RedirectView
はDispatcherServlet
からView#render(Map, HttpServletRequest, HttpServletResponse)
が呼び出される。 RedirectView
の継承元のAbstractView
にrender
メソッドの実装があり、そこで必要なモデルを抽出、ヘッダーに値を設定した後にrenderMergedOutputModel
を呼び出す。RedirectView#renderMergedOutputModel(Map, HttpServletRequest, HttpServletResponse)
にて引数として返したurlにクエリーなどを付加したurlを作る。RedirectView
で先ほどのurlをHttpServletResponse.sendRedirect(String)
にそのまま流す。
単純には次のような形で返すURLをエンコーディングすればよいだけ。
@GetMapping(path = "bar") String somePage() throws Exception { return "redirect:/to/" + URLEncoder.encode("日本語", "UTF-8") + "url" ; }
とはいえ、日本語URLが大量にあるアプリケーションだと、それもつらいので、次のようなクラスを作ってリダイレクトしてみるとよいかもしれない。
public class EncodingRedirectView extends RedirectView { public EncodingRedirectView(final String url, final boolean contextRelative) { super(encodeUrl(url), contextRelative); } private static String encodeUrl(final String url) { return Arrays.stream(url.split("/")).map(unhandle(p -> URLEncoder.encode(p, "UTF-8"))).collect(joining("/")); } private interface UnHandleFunction<A, B> { B apply(final A a) throws Exception; } private static <A, B> Function<A, B> unhandle(final UnHandleFunction<? super A, ? extends B> function) { Objects.requireNonNull(function); return a -> { try { return function.apply(a); } catch (Exception e) { throw new RuntimeException(e); } }; } }
むしろよい方法あったら、誰か教えて…
2018/01/04 9:42 追記
次のように RedirectAttributes
を使う方法があるらしい
@GetMapping String somePage(final RedirectAttributes attributes) { attributes.addAttribute("path", "日本語url"); return "redirect:/to/{path}"; }