問題
- Angular で HttpClient を使って HTTP リクエストを送信するとき HttpParams を使ってパラメータを指定するとパラメータの値がエンコードされていないように見える
let params = new HttpParams();
params = params.append("date", new Date().toISOString());
console.log(params.toString()); // date=2019-12-06T04:26:52.880Z
- それならとパラメータの値を
encodeURIComponent()
すると一見問題なさそうだが%
が%25
にエンコードされてしまい二重にエンコードされているように見える
let params = new HttpParams();
params = params.append("date", encodeURIComponent(new Date().toISOString()));
console.log(params.toString()); // date=2019-12-06T04%253A28%253A17.828Z
なにがおこっているか
- HttpParams はエンコードをしていないように見えるが、実際には RFC3986 に従ってエンコードを行っている
-
実装としては
encodeURIComponent()
したあとに@$:,;+=?/
をデコードしている
どうしたらいい感じにエンコードできるか
- HttpParams のコンストラクターで HttpParameterCodec を実装したエンコード用のオブジェクトを指定できるので
encodeURIComponent()
するだけのクラスを実装して指定してあげれば良い
エンコーダの実装
export class BrowserStandardEncoder implements HttpParameterCodec {
encodeKey(key: string): string {
return encodeURIComponent(key);
}
encodeValue(value: string): string {
return encodeURIComponent(value);
}
decodeKey(key: string): string {
return decodeURIComponent(key);
}
decodeValue(value: string): string {
return decodeURIComponent(value);
}
}
エンコーダを初期化時に指定する
let params = new HttpParams({encoder: new BrowserStandardEncoder()});
params = params.append("date", new Date().toISOString());
console.log(params.toString()); // date=2019-12-06T04%3A30%3A45.959Z