web-dev-qa-db-ja.com

ブラウザーから消費されるバイナリー・データを使用して残りのWebサービスを設計するための最良のアプローチ

私は、backbone.jsで構築された単一のWebページアプリから使用されるjson rest Webサービスを開発しています

このAPIにより、プロジェクトに関連するPDFレポートなど、一部のエンティティに関連するファイルをユーザーがアップロードできるようになります

ぐるぐる回ってスタックオーバーフローでいくつかの調査を行うと、次のようなアプローチが可能になりました。

最初のアプローチ:base64エンコードされたデータフィールド

POST: /api/projects/234/reports
{
  author: 'xxxx',
  abstract: 'xxxx',
  filename: 'xxxx',
  filesize: 222,
  content: '<base64 encoded binary data>'
}

2番目のアプローチ:マルチパートフォームポスト:

POST: /api/projects/234/reports
{
  author: 'xxxx',
  abstract: 'xxxx',
}

応答として、レポートIDを取得します。これで、別の投稿を発行します

POST: /api/projects/234/reports/1/content
enctype=multipart/form-data

そして、バイナリデータを送信します

(これを見てください: https://stackoverflow.com/a/3938816/476

3番目のアプローチ:バイナリデータを別のリソースに投稿し、hrefを保存します

まず、クライアントでランダムキーを生成し、そこにバイナリコンテンツを投稿します

POST: /api/files/E4304205-29B7-48EE-A359-74250E19EFC4
enctype=multipart/form-data

その後

POST: /api/projects/234/reports
{
  author: 'xxxx',
  abstract: 'xxxx',
  filename: 'xxxx',
  filesize: 222,
  href: '/api/files/E4304205-29B7-48EE-A359-74250E19EFC4'
}

(これを参照してください: https://stackoverflow.com/a/4032079/476

私が使用できるアプローチが他にあるかどうか、それぞれの長所/短所、およびこの種の要件に対処する確立された方法があるかどうかを知りたかっただけです

私が最初のアプローチで見る大きな欠点は、クライアントでファイルを完全にロードしてbase64エンコードする必要があることです

いくつかの有用なリソース:

31
opensas

私の研究結果:

  1. 単一リクエスト(データを含む)

    リクエストにはメタデータが含まれています。データはメタデータのプロパティであり、エンコードされています(例:Base64)。

    長所:

    • トランザクション
    • 常に有効(欠落していないメタデータやデータはありません)

    短所:

    • エンコードするとリクエストが非常に大きくなります

    例:

  2. 単一リクエスト(マルチパート)

    リクエストには、メタデータとデータを含む1つ以上の部分が含まれています。

    コンテンツタイプ:

    長所:

    • トランザクション
    • 常に有効(欠落していないメタデータやデータはありません)

    短所:

    • コンテンツタイプネゴシエーションは複雑です
    • [〜#〜] wadl [〜#〜] でデータのコンテンツタイプが表示されない

    例:

    • Confluence (データおよびメタデータ用のパーツを使用)
    • Jira (データ用の1つの部分、ファイル名とMIMEタイプのメタデータのみの部分ヘッダー)
    • Bitbucket (データ用に1つの部分、メタデータなし)
    • Googleドライブ (メタデータ用に1つのパーツとパーツデータ用に1つのパーツ)
  3. 単一のリクエスト(HTTPヘッダーとURLのメタデータ)

    リクエストの本文にはデータとHTTPヘッダーが含まれ、URLにはメタデータが含まれます。

    長所:

    • トランザクション
    • 常に有効(欠落していないメタデータやデータはありません)

    短所:

    • ネストされたメタデータは不可能
  4. 2つのリクエスト

    メタデータの1つのリクエストとデータの1つ以上のリクエスト。

    長所:

    • スケーラビリティー(例:データ要求はリポジトリー・サーバーに送信される可能性があります)
    • 再開可能(例 Google Drive を参照)

    短所:

    • トランザクションではない
    • 常に有効ではありません(2番目のリクエストの前に、一部が欠落しています)

    例:

14
dur

私は頭の上から他のアプローチを考えることはできません。

あなたの3つのアプローチのうち、私は方法3を最もよく使用しました。私が目にする最大の違いは、最初の方法と他の方法2の違いです:メタデータとコンテンツを2つのリソースに分離する

  • プロ:スケーラビリティ
    • ソリューションには同じサーバーへの投稿が含まれますが、コンテンツのアップロードが別のサーバー(Amazon S3など)を指すように簡単に変更できます。
    • 最初の方法では、ユーザーにメタデータを提供する同じサーバーで、大規模なアップロードによってプロセスがブロックされます。
  • 短所:孤立したデータ/複雑さの追加
    • 失敗したアップロード(メタデータまたはコンテンツ)は、孤立したデータをサーバーDBに残します
    • 孤立したデータはスケジュールされたジョブでクリーンアップできますが、これによりコードが複雑になります
    • 方法IIでは、最初のPOSTの応答をブロックしているため、クライアントの待機時間が長くなる代わりに、孤立の可能性が減少します。

最初の方法は、コーディングが最も簡単なようです。ただし、このサービスの使用頻度が低いことが予想され、ユーザーファイルのアップロードに適切な制限を設定できる場合にのみ、最初の方法を使用します。

8
Eric Hu

究極の方法は、HTTP標準から取得した値を最大化できるという主な理由から3番目(個別のリソース)であると考えています。これは、REST APIの考え方に一致します。たとえば、十分に接地されたHTTPクライアントが使用されているとすると、次の利点があります。

  • コンテンツ圧縮:クライアントがサポートを示し、APIが変更されていない場合、既存のクライアントが引き続き機能し、将来のクライアントの場合、サーバーが圧縮結果で応答できるようにして最適化しますそれを利用することができます
  • Caching:If-Modified-Since、ETagなど。クライアントはバイナリデータの完全な再フェッチを回避できます。
  • コンテンツタイプ抽象化:たとえば、アップロードされた画像が必要です。タイプはimage/jpegまたはimage/png。 HTTPヘッダーAcceptおよびContent-typeは、いくつかのエレガントなセマンティクスを提供しますスキーマやAPIの一部としてハードコードする必要なしに、クライアントとサーバー間でこれをネゴシエートします。

一方、問題のバイナリデータがオプションでない場合、この方法が最も単純ではないと結論付けるのは公平だと私は思います。その場合、 Eric Huの答え にリストされている短所が出てきます。

5
Amr Mostafa