url エンコーディングと uri の仕様
1時に寝ようとして、寝てたか起きてたかわからない時間を過ごして7時に起きた。
WebClient と query string のエンコーディング⌗
以前にも WebClient の基本 について少し書いた。data={"x": 1, "y": 2}
のような json 文字列を query string でリクエストしようとしたときに少しはまったので書いておく。java 標準ライブラリの URLEncoder を使ってエンコードするとスペースが +
になる。これは html の仕様として正しいが、uri の仕様としては不正になる。そのため +
を %20
に置き換える必要がある。
private String encode(String data) throws UnsupportedEncodingException {
// NOTE: the URI doesn't allow '+' character
return URLEncoder.encode(data, StandardCharsets.UTF_8).replace("+", "%20");
}
このロジックで {"x": 1, "y": 2}
を url エンコードすると次の文字列になる。
%7B%22x%22%3A%201%2C%20%22y%22%3A%202%7D
あらかじめ url エンコーディングした文字列を渡すと、今度は WebClient が %
を %25
にさらにエンコーディングしてしまう。Spring WebClient Requests with Parameters 6.Encoding Mode によると、次の4つのエンコーディングモードをカスタマイズできる。デフォルトは TEMPLATE_AND_VALUES らしい。
- TEMPLATE_AND_VALUES: Pre-encode the URI template and strictly encode URI variables when expanded
- VALUES_ONLY: Do not encode the URI template, but strictly encode URI variables after expanding them into the template
- URI_COMPONENTS: Encode URI component value after expending URI variables
- NONE: No encoding will be applied
もとの url エンコード済みの文字列が次のようなものになってしまう。
%257B%2522x%2522%253A%25...
既存の実装をあまり変えたくもなくてやや力技で実装した。局所的な変更だからまぁいっか。
webClient.get().uri(uriBuilder -> {
var uriObj = uriBuilder.path(getControllerBasePath() + path).queryParams(query).build(pathParams);
if (encodedData != null) {
var uri = uriObj.toString();
var connector = uri.contains("?") ? "&" : "?";
uriObj = URI.create(String.format("%s%sdata=%s", uri, connector, encodedData));
}
return uriObj;
}).retrieve()
よいエラーメッセージ、わるいエラーメッセージ⌗
タイトルに惹かれてちょっと期待外れ。art というと日本人は芸術と高度なものを期待しがちだけど、the art of だと技術の体系といった意味合いもあるのでちょとしたノウハウを解説する技術ブログのようなものでも誤っていない。
ユーザー体験をよくするためのエラーメッセージのコツとして次の3つを提案している。
- 何が起きたのか、なぜ起きたのかを説明する
- 次のステップを提案する
- 適切なトーンで書く
この3つの具体例としてどのようなものかを説明している。私にとってはそう目新しいものではないが、エラーメッセージにトーンという概念はなかったので最近の流行りなのかなと思った。