Purpose
AngularのアプリケーションをIISにデプロイしたとき、Http Status 400 : Bad Requestのエラーが出てはまったときの対応方法についてまとめる
背景
A画面から、B画面に遷移する処理があった。この時、A画面で入力された複数のパラメータをB画面に渡す必要があった。複数のパラメータは、1つのクラスのインスタンスとして保持しているため、以下の方法でA→Bに受け渡すようにした。
A画面にて・・・
1. パラメータのインスタンスを作成する。(パラメータクラスには複数のプロパティがある。)
2. Json形式に変換する。
3. Json Stringをbtoaクラスを使ってBase64エンコードする。
4. ActivatedRouteのparams引数に、3.のエンコード済み文字列を設定し、画面遷移を実行する。
B画面にて・・・
1. paramsで受け取った文字列をBase64デコードする。
2. Json Stringをデシリアライズし、パラメータクラスのインスタンスに設定する。
3. パラメータの受け渡し成功。B画面の処理を行う。
この時、受け渡すパラメータの値によって、Base64エンコードした後の文字列が260文字を超えることがあった。
問題
ローカルでng serveを利用してデバッグしていても特に問題はなかった。しかし、IISにデプロイし、挙動を確認すると、A画面からB画面に遷移するものの、B画面で画面をリロードするなどして、B 画面へのURLをたたくと、Http Status code :400 bad requestが表示されるという現象が発生した。
原因
B画面に遷移する際URLは次のような形式となる。※Base64Stringには、Bas64でエンコードされた長い文字列が入る。
http://localhost/B画面/Base64String
この時、A画面→B画面に遷移する際は、Angular内で閉じた処理となる。AngularがデプロイされているWeb Server(IIS)には、リクエストが飛ばないため、想定通りのURLと、パラメータが認識されて画面遷移が実行される。
しかし、ページのリロードなど、直接上記のURLをリクエストすると、いったんWeb Serverにリクエストが送信される。リクエストを受け取ったIIS
IISは、Web Applicationがデプロイされているサイトのルートディレクトリから、./B画面/Base64Stringというフォルダに配置されたリソースを探しに行く。Windowsのデフォルト設定で、Windowsのフォルダ名は260文字という制約がある。そのため、上記含まれるBase64Stringのフォルダを探す際、そんな長さの名前のリソースはない=URLが不正な値である、とに認識されBad Requestが返されるという流れであった。
対応
実際の対応
Angularには、パラメータとして値を伝える方法のほかに、Query Stringを使った方法もサポートされている。Angularでクエリパラメータを使用する方法。
長い文字列を別画面に伝えるばあい、Query Stringを使った方法でやると、上記の問題は回避することができる。
そのほかに考えた方法
ローカルでng serveがうまくいっているなら、ng serveを使うようにしちゃえばいいやんと考えた。しかし、StackOver flowからの引用にもある通り、これは、開発時に利用するための開発サーバーであるため、本番デプロイで利用することは避けたほうが良い。
You should not use ng serve for production because it use webpack-dev-server that is build for development only.
まとめ
長い文字列をパラメータとして別画面に伝播するときは、URL直接アクセスを考慮してQuery Stringを利用する方式にするのがよさそう。