きなこもち.net

.NET Framework × UiPath,Orchestrator × Azure × AWS × Angularなどの忘備録

Angular画面遷移 × Bad Request × 長い文字列を別画面に送ろうとしてはまった点について

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を利用する方式にするのがよさそう。