HATEOASを使用したRESTful Webサービスの設計において、リンクを完全なURLとして表示することの賛否両論( " http:// server:port/application/customers/1234 ")と単なるパス( "/ application/customers/1234")?
人々が「相対URI」と言うとき、微妙な概念のあいまいさがあります。
RFC3986の定義 により、汎用URIには以下が含まれます。
_ URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
hier-part = "//" authority path-abempty
/ path-absolute
/ path-rootless
/ path-empty
foo://example.com:8042/over/there?name=ferret#nose
\_/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
_
トリッキーなことは、スキームと権限が省略されている場合、「パス」部分自体が絶対パス(_/
_で始まる)または「ルートレス」相対パスのいずれかになる可能性があることです。例:
"http://example.com:8042/over/there?name=ferret"
_/over/there
_here
または_./here
_または_../here
_などです。したがって、「サーバーが安静時の応答で相対パスを生成するかどうか」という質問の場合、答えは「いいえ」で、 詳細な理由はこちら です。 「相対URI」に反対するほとんどの人(私を含む)は、実際には「相対パス」に反対していると思います。
そして実際には、ほとんどのサーバー側MVCフレームワークは_/absolute/path/to/the/controller
_のように絶対パス付きの相対URIを簡単に生成でき、問題は「サーバー実装が_scheme://hostname:port
_の前に付けるかどうか」になります。絶対パスの前」。 OPの質問のように。これについてはよくわかりません。
一方で、サーバーは完全なURIを返すことをお勧めします。ただし、サーバーは このようなソースコード内の_hostname:port
_をハードコードしないでください (それ以外の場合は、絶対パスを使用して相対URIにフォールバックします)。解決策は、サーバー側が常にHTTPリクエストの「ホスト」ヘッダーからそのプレフィックスを取得することです。ただし、これがすべての状況で機能するかどうかはわかりません。
一方、クライアントが_http://example.com:8042
_と絶対パスを連結することはそれほど面倒ではないようです。結局のところ、クライアントがサーバーに要求を送信するとき、クライアントは既にそのスキームとドメイン名を知っていますか?
全体として、絶対URIを使用することをお勧めします。絶対パスを使用して相対URIにフォールバックする可能性があり、相対パスは使用しないでください。
誰がクライアントコードを書いているのかによります。クライアントとサーバーを作成している場合は、それほど大きな違いはありません。クライアント上またはサーバー上でURLを構築するという苦痛に苦しむことになります。
ただし、サーバーを構築していて、他の人がクライアントコードを書くことを期待している場合は、完全なURIを提供すれば、他の人があなたをもっと好きになるでしょう。相対URIの解決は少し難しい場合があります。最初にそれらを解決する方法は、返されるメディアタイプによって異なります。 HTMLにはベースタグがあり、Xmlにはすべてのネストされた要素にxml:baseタグを含めることができます。Atomフィードは、フィードにベースを、コンテンツに別のベースを含めることができます。クライアントがベースURIに関する明示的な情報を持っている場合は、リクエストURIまたは多分Content-LocationヘッダーからベースURIを取得する必要があります!また、末尾のスラッシュに注意してください。ベースURIは、これは、相対URIを解決するときに末尾のスラッシュが非常に重要になることを意味します。
小さな言及が必要な他の唯一の問題は、ドキュメントのサイズです。各アイテムに複数のリンクがある可能性があるアイテムの大きなリストを返す場合、エンティティを圧縮しないと、絶対URLを使用すると、エンティティにかなりの量のバイトが追加される可能性があります。これはパフォーマンスの問題であり、ケースバイケースで重要かどうかを判断する必要があります。
唯一の本当の違いは、クライアントが相対バージョンから構築するのではなく、絶対URIを消費する方がクライアントにとっては簡単であることです。もちろん、その違いは私を絶対バージョンにするのに十分です。
アプリケーションのスケーリングに応じて、負荷分散やフェイルオーバーなどを実行したい場合があります。絶対URIを返す場合、クライアント側のアプリはサーバーの進化する構成に従います。
RayLouのtrichotomy を使用して、私の組織は(2)を優先することを選択しました。主な理由は、XSS(クロスサイトスクリプティング)攻撃を回避するためです。問題は、攻撃者がサーバーから返される応答に独自のURLルートを挿入できる場合、その後のユーザー要求(ユーザー名とパスワードを使用した認証要求など)が攻撃者自身のサーバーに転送される可能性があることです*。
負荷分散のためにリクエストを他のサーバーにリダイレクトできるという問題を提起している人もいますが、(それは私の専門分野ではありませんが)クライアントを明示的に別のクライアントにリダイレクトすることなく、負荷分散を有効にするより良い方法があると思います。ホスト。
*この推論の行に欠陥があるかどうか私に知らせてください。もちろん、目標はすべての攻撃を防ぐことではなく、少なくとも1つの攻撃方法を防ぐことです。
常に完全なURLを使用する必要があります。 URLはすべて一意である必要があるため、リソースの一意の識別子として機能します。
私はあなたが首尾一貫しているべきだとも主張します。 Location HTTPヘッダーはHTTP仕様に基づく完全なURLを想定しているため、新しいリソースが作成されると、完全なURLがLocationヘッダーでクライアントに送り返されます。 Locationヘッダーに完全なURLを指定してから、応答本文内のリンクに相対URIを指定するのはおかしいでしょう。
絶対URIを使用する場合の1つの欠点は、APIをプロキシできないことです。
それを取り戻す...本当ではない。ドメインを含む完全なURLを取得する必要があります。
長所に関しては、クライアントが(絶対)パスに必要とする追加の処理を犠牲にして、送信されるバイト数が削減されることを確認しました。すべてのバイトを節約したい場合は、gzipとしてコンテンツエンコーディングを試みた後でも、キャッシュヘッダーの適切な使用、etagsの使用、クライアントでの条件付きリクエストの場合、最終的にこれが必要になるかもしれませんが、あなたの努力は別でした。
短所に関しては、将来的にリソース間のクライアントのフローをどのように方向付けることができるかについての制御が失われる(負荷分散、A/Bテストなど)と思います。これは、Webの管理に関しては悪い習慣だと思いますAPI。あなたが提供するURLは基本的にクライアントにとって不透明ではありません(Tim Berners-Lee RI不透明度に関するWebアーキテクチャの公理 を参照)。最終的には、URLスペースの構造だけが関係している場合でも、APIのクリエイティブな使用法についてクライアントを満足させる責任があります。明示的に定義されたURLの変更を許可する必要がある場合は、 ハイパーテキストアプリケーション言語 で使用される RIテンプレート の使用を検討してください。
大規模なAPI結果で重要な考慮事項は、完全なURIを繰り返し含めることによる追加のネットワークオーバーヘッドです。信じられないかもしれませんが、gzipはこの問題を完全には解決しません(理由はわかりません)。結果に何百ものリンクが含まれている場合に、URI全体が占めるスペースにショックを受けました。