第6話: HTTPウェブプッシュ の雑多なメモ 〜 REAL WORLD HTTP第7章より 〜
yagisuke.hatenadiary.com の第6話<最終回>です。
HTTPウェブプッシュ
HTTPウェブプッシュは、ウェブサイトにスマホアプリのような通知機能を提供する仕組みです。 HTTPウェブプッシュはその機能の特性上、ブラウザが起動していなかったり、 オフラインでも、ユーザに通知を送れる必要があります。
サイバーエージェントさんのFRESH!というサービスで使われているです。 画像: https://developers.cyberagent.co.jp/blog/archives/9772/
実装方法や困ったことも記載していて面白そうな記事になっているのでオススメしておきます。 - https://developers.cyberagent.co.jp/blog/archives/9662/
また、ディレクターがHTTPウェブプッシュを導入することで考えていたことも別記事になっていて面白そうです。 - https://developers.cyberagent.co.jp/blog/archives/9772/
Service Worker
ブラウザがないのになぜ通信できるのか。 その秘密は、オフラインのアプリを実現・サポートするために作られた Service Workerという機能にあります。
Service Workerは、ブラウザがWebページのスクリプトとは別のプロセスでスクリプトを バックグラウンドで実行できる機能のことです。現在登録されているイベントは以下の通りとなっています。
呼ばれるタイミング | イベント名 |
---|---|
インストール時 | activate |
フロントエンドからのpostMessage() | message |
フロントエンドがサーバーにアクセス | fetch |
プッシュ通知受信 | push |
HTTPウェブプッシュの流れ
引用元: http://d.hatena.ne.jp/jovi0608/20141204/1417697480
どのような仕組みで行われるのか、その概要を一枚の図にしました。 ちょっとごちゃごちゃ説明文を図に書いていますが登場人物は3人、
- クライアント(ブラウザには、Webアプリケーション(Web App)、Service Worker、Push APIが動いています)
- Webアプリケーションのサーバ(app.example.jp)
- プッシュサーバ(push.example.jp) です。
画像: http://d.hatena.ne.jp/jovi0608/20141204/1417697480
ざっとした流れは、
- クライアントからプッシュサーバの登録情報(endopoint, registrationID)をアプリサーバに通知。 (Push Serviceにアプリサーバがリクエストを送ることができるようになる)
- アプリサーバが、プッシュ通知をHTTP PUTのリクエストボディに付けてプッシュサーバに送信。
- プッシュサーバは、プッシュ通知をチャネルで区別し、送信クライアントを選定。
- プッシュサーバは、HTTP/2のサーバプッシュやFCM(Firebase Cloud Messaging)など利用してクライアントにプッシュ通知をSSEで送信。
- クライアントは、プッシュサーバからプッシュ通知を受けると、Service Worker上でPushイベントが発生。
- プッシュされたデータはキャッシュ更新なり、クライアント上でいかようにでも処理することができる。
といった流れになります。
事前作業が必要
上記1に入る前に、ブラウザを起動するときに、プッシュ通知の利用許諾を取る必要があります。 - プッシュ通知はオプトイン(承諾が必要ってこと) - 承諾されればプッシュサービスを利用登録する - サービスのIDと、送信用の鍵(プッシュサービスがブラウザを特定するためのもの)を取得
承諾されて有効になるとService Workerで登録したpushイベントで 通知が受け取れるようになります。
補足:
現状ウェブプッシュはプッシュサービスと連携することで実現しています。 プッシュサービスはChromeの場合はGoogle社の通知サービス、 Firefoxの場合はMozilla社の通知サービスを利用します。
緊急度の設定
Urgencyヘッダーをリクエスト時に付与すると、不必要なメッセージをフィルタリングできます。 メッセージ送信、および送信のときに付与します。 以下のように設定可能な値を示します。 省略時はnormalになります。
緊急度 | デバイスの状態 | 用途 |
---|---|---|
very-low | 電源がつながっていてWiFi接続あり | 広告 |
low | 電源がつながっているか、WiFiあり | 話題の更新 |
normal | 電源がつながっておらず、WiFiもない | チャットやカレンダーのメッセージ |
high | バッテリー残量が少ない | 電話の着信、もしくは時間厳守の通知 |
引用元や参考情報
第5話: WebRTC の雑多なメモ 〜 REAL WORLD HTTP第7章より 〜
の第5話です。
WebRTC(Web Real-Time Communication)
WebRTCはブラウザ/サーバー間の通信だではなく、ブラウザとブラウザのP2P通信で使用します。 RTCは「リアルタイムコミュニケーション」の略で、テレビ電話などのリアルタイムコミュニケーションを 実現するための基盤として設計されています。
実現したいアプリケーションも他のプロトコルとは大きく異なるため、使われる機能群も大きく変わります。 通信の基盤に使うトランスポート層は、再送処理の面倒を見てくれるTCPではなく、 エラー処理や再送処理を行わないUDPをメインで使います。
またP2P通信なので、相手もブラウザを探すシグナリング、ルーター内部のプライベートアドレスしか 持たないコンピューターで動いているブラウザのため、NATを超えてプライベートアドレスだけで通信 できるような技術も使われています。
RTCPeerConnection
WebRTCの技術要素について説明していきますが、 ブラウザから使われるAPIという観点で説明していきます。
- RTCPeerConnection: 通信経路の確保とメディアチャンネルのオープン
- mediaDevices.getUserMedia: カメラ、マイクと動画・音声のハンドリング
- RTCDataChannel: データチャンネルの通信
WebRTCのベースになっているのはIP電話です。 IP電話で使われている技術を一つにまとめ、JavaScriptのAPIを定めたものです。 NAT超えなどの基礎をなすプロトコルはどれも古くからあるものです。
IP電話についてはこちら: http://www.pc-master.jp/internet/ip-denwa.html
P2P通信を確立するまで
ブラウザ間でP2P通信を行うには、相手のIPアドレスを知らなくてはなりませんし、 動的に割り振られるUDPのポート番号も知る必要があります。 また、その通信でやり取りできる内容についても、お互い合意しておく必要があります。 そのためP2P通信が確立するまでに、WebRTCではいくつかの情報をやり取りしています。
ICE(Interactive Connectivity Establishment)
ICEはNATを超えてP2P通信の接続を確立する手法です。 STUNとTURNのどちらかのサーバーを利用します。
(今回はSTUNで説明します)
NATを越えてP2P通信するには、シグナリング処理でお互いに自分の知らないグローバルの情報を 交換する必要があります。
画像: https://html5experts.jp/mganeko/20618/
自分で知らない情報は、誰かから教えてもらうしかありません。 それを可能にするのがSTUNです。
STUNの仕組みはシンプルです。 NATで変換されたIPアドレス/ポートを、外側にいるSTUNサーバーに教えてもらいます。 先ほどの例で言えば、このようになります。
画像: https://html5experts.jp/mganeko/20618/
自分のグローバル情報が分かったら、それをシグナリングサーバー経由で相手に渡します。 STUNサーバーから得られた情報は、シグナリングの過程でICE Candidateとして取得できます。 これをシグナリングサーバーなどを経由して相手に送ることができ、P2P通信が実現しています。
画像: https://html5experts.jp/mganeko/20618/
SDP(Session Description Protocol: セッション記述プロトコル)
SDPはP2Pのネゴシエーション時に互いのIPアドレストポート、双方で利用できるオーディオや動画の コーデック情報を共有するためのものです。
コーデック (Codec) は、符号化方式を使ってデータのエンコード(符号化)とデコード(復号)を双方向 にできる装置やソフトウェアなどのこと。 また、そのためのアルゴリズムを指す用語としても使われている。
参照: https://ja.wikipedia.org/wiki/コーデック
WebRTCでは「自分が使えるコーデック情報やIPアドレスなどをSDPというプロトコルのフォーマットで 記述して相手に渡し、相手からも互いに利用可能なコーデック情報のレスポンスをもらう」という手続きを 定めていますが、「相手に渡す」手段は定めていません。
渡す手段とかはこちらを参照すると良いとのことです。
https://html5experts.jp/mganeko/19814/
メディアチャンネルとgetUserMedia
相手との通信が確立したら、実際に通信を行います。 音声やビデオを取り扱うのがメディアチャンネルです。
navigator.mediaDevices.getUserMedia()
ビデオ会議などで使うウェブカメラやオーディオデバイスの、設定と取得を行うブラウザAPIです。
カメラは解像度、フレームレート、フロントカメラ/リアカメラなどを指定することもできます。 取得されたものはストリームという名前で呼ばれます。 このAPIは単独でも使うことができ、HTMLのvideoタグ上にカメラの映像を表示できます。
APIについて: https://developer.mozilla.org/ja/docs/Web/API/MediaDevices/getUserMedia
オーディオはWeb Audio APIを利用することで高度な制御やモニタリングが行えます。 ステレオの音位の指定やミキシング、ボリューム調整などができます。 Audio Workerを利用すると音声信号をJavaScriptで分析できるようになるため、 しゃべっている人の検出なども可能となります。
Web Audio APIについて: https://developer.mozilla.org/ja/docs/Web/API/Web_Audio_API
DTLS
WebRTCのデータ通信には、メディアチャンネルとデータチャンネルの2つがあります。 どちらも、DTLS上の通信となっています。
DTLSについてはこちら
参考: http://www.nttpc.co.jp/yougo/DTLS.html
メディアチャンネル
音声・動画を伝送するWebRTC Mediaチャンネルです。 WebRTC MediaチャンネルはDTLS上のSRTPというプロトコルをつかっています。
- S: セキュリティ
- RTP: リアルタイムプロトコル
音声や動画のストリーミングで情報が入れ替わってしまうのは問題なので、 順序の整列機能だけをUDPに追加しています。
データチャンネル
データチャンネルは音声以外のデータをP2Pで送受信するためのものです。 ユースケースにはファイルをチャットの相手に送信したり、 通信対戦のゲームの捜査情報を共有するのに使用していました。 データチャンネルはDTLSの上でSCTP(Stream Control Transmission Protocol)という プロトコルを載せています。
データのユースケースは映像・音声よりも多少幅があります。 データファイルのデータが途中で消失してしまったり、一部欠落すると困ることもあれば、 それより応答性が損なわれる方が問題になることもあります。
そこでSCTPではパフォーマンスとトレードオフで信頼性を設定できるようになっています。 UDP側に寄せるか、TCP側に寄せるか、選べるようになっています。
TCP | UDP | SCTP | |
---|---|---|---|
信頼性 | 到達保証あり | 到達保証なし | 変更可能 |
配送順序 | 順序付けあり | 順序つけなし | 変更可能 |
転送方式 | バイト指向 | メッセージ指向 | メッセージ指向 |
輻輳制御 | あり | なし | あり |
データチャンネルの初期化は以下のように行います。 2つ目の引数が特性を制御するパラメータです。 省力時はTCP同等の配送順序保証の高信頼性モードになります。 このサンプルコードは順序を保証せず、再送もしないというUDP互換のモードを設定しています。 maxRetransmitTimeかmaxRetransmitsのどちらかを設定し、再送方式を手動にすると非信頼モードになります。
const connection = new RTCPeerConnection() const dataChannel = connection.createDataChannel('data channel', { orderd: false, // 順序保証? maxRetransmitTime: 0, // 再送し続ける期間 maxRetransmits: 0 // 再送回数 })
ファイル送信などのユースケースであればデフォルトの高信頼性モードが適しています。 例えば、画像ファイルやEXCELファイルのデータの一部が変えたり順序が入れ替わってしまったら、 ファイルとして用をなさないからです。 ゲームのステータスで、UDPの1パケットに治るサイズであれば、少なくとも順序保証はありません。
参考になりそうなサイト: https://www.html5rocks.com/ja/tutorials/webrtc/datachannels/
引用元や参考情報
第4話: WebSocket の雑多なメモ 〜 REAL WORLD HTTP第7章より 〜
yagisuke.hatenadiary.com の第4話です。
WebSocket
WebSocketとは、サーバー/クライアント間で、オーバーヘッドの小さい双方向通信を実現する仕組みです。
WebSocketはフレーム探知で送受信しますが、相手が決まっているために送信先の情報などはもちません。 HTTPの基本要素のうち、ボディのみを送っているようなものです。 フレームはデータサイズなどを持っているだけで、オーバーヘッドも2から14バイトしかありません。 一度コネクションを確立した後は、サーバーとクライアントのどちらからも通信を行うことが可能です。
WebSocketは何がうれしいのか
Ajax, Commet, WebSocketの通信の比較を電話で表現してみたの図です。
画像: https://www.slideshare.net/You_Kinjoh/websocket-10621887 P.34
(備考: 一回返事をもらうごとに通信が切れる気がするけど、)
画像: https://www.slideshare.net/You_Kinjoh/websocket-10621887 P.35
画像: https://www.slideshare.net/You_Kinjoh/websocket-10621887 P.36
画像: https://www.slideshare.net/You_Kinjoh/websocket-10621887 P.37
通信方式 | 特徴 |
---|---|
Ajax | 負荷が高い サーバー側の情報取得は定期的 クライアント側の情報送信は別接続で行うことが多い |
Commet | 負荷が非常に高い サーバー側の情報取得はリアルタイム クライアント側の情報送信は別接続のAjax |
WebSocket | 負荷が小さい サーバー側の情報取得はリアルタイム クライアント側の情報送信も同じ接続内(双方向通信) |
WebSocketはステートフル
WebSocketが他のHTTPベースのプロトコル異なるのは「ステートフルな通信である」という点です。
ステートフルとかステートレスについて: http://yohei-y.blogspot.jp/2007/10/blog-post.html
HTTPは高速性のためにKeep-Aliveなどの複雑な機構も備えるようになってきていますが、 基本的にリクエスト単位で接続が切れてもセマンティクス上は問題ありません。 ロードバランサーを使ってサーバーを複数台に分散しておき、リクエストのたびに別のサーバーが 応答していても問題ありません。
ちなみに、Server-Sent Eventsも送信済みIDを一元管理して保証できれば、 リクエストを捌くサーバーが入れ替わっても問題がないように設計されています。
JavaScriptのクライアントAPI
WebSocketは、HTTPの下のレイヤーであるTCPソケットに近い機能を提供するAPIです。 JavaScriptのAPIもTCPソケットのAPIに近い形態になっています。 通信はサーバーが受信を受けている状態で、必ずクライアントから接続します。 (クライアント起点の通信)
- サーバーが特定のIPアドレス、ポート番号でサーバーを起動(Listen)
- クライアント(ブラウザ)がサーバーに通信開始の宣言をする(Connect)
- サーバーにクライアントから接続依頼がくるので、それを受け入れる(Accept)
- サーバーにはソケットクラスのインスタンスが渡される
- サーバーが受理すると、クライアントのソケットのインスタンスの送受信機能が有効になる
このListen/Connect/Acceptは筆者が参考のために追加したもので、 システムプログラミングの文脈でソケットについて説明するときに使われる関数名です。
JavaScriptのWebSocketのAPI名はこれと異なりますが、基本的な考え方に差はありません。 実際には一旦HTTPで接続してからアップグレードするため、内部の手順はやや複雑ですが、 外部から見たシーケンスは同じです。 基本的な接続と送信のコードを示します。 WebSocketクラスのコンストラクタで接続先のURLを指定して、send()メソッドでデータを送信します。
上記の手順でクライアントが接続に当たってすべきことは2つだけです。 このコンストラクタと、onopenイベントリスナの裏でこれだけのことが行われています。
const socket = new WebSocket('ws://game.example.com:12010/updates') socket.onopen = () => { // データの送受信可能となる setInterval(() => { if (socket.bufferedAmount === 0) { socket.send(getUpdateData()) } }) }
接続後のソケットに対して、クライアント側で行う操作は次の3つです。 - send([データ]): WebSocket接続を利用して、データをサーバーに送信する - onmessage: サーバーからメッセージを受信した時に呼ばれるイベントリスナ - close([コード [, 理由]]): WebSocket接続を切断
データとしては文字列、Blob, ArrayBufferなどを使うことができます。 受信には、onmessageメソッドを使います。 onmessageイベントの使い方はServer-Sent Eventsと同じです。
参考: https://developer.mozilla.org/ja/docs/Web/API/WebSocket
接続
まず通常のHTTPとして接続をスタートし、その中でプロトコルのアップグレードを行い、 WebSocketにアップグレードすることを要請します。
通常開始のリクエスト
GET /chat HTTP/1.1 // 普通のHTTPリクエスト Host: server.example.com Origin: http://example.com Upgrade: websocket // この2つで、HTTPからWebSocketへの Connection: Upgrade // プロトコルのアップグレードを表現している Sec-WebSocket-Key: A4QSEcsepWr4m2PLS2PJHA== Sec-WebSocket-Version: 13 Sec-WebSocket-Protocol: chat, superchat
- Sec-WebSocket-Key クライアントとのコネクションの確立を立証する為に使われる。 ランダムに選ばれた16バイトの値をBASE64エンコードした文字列
- Sec-WebSocket-Versions 接続のプロトコルバージョンを指示するためにクライアントからサーバへ送信され、 現在のWebSocketの最新バージョンは13なので13を固定する
- Sec-WebSocket-Protocol WebSocketは単にソケット通信の機能だけを提供する。 その中でどのような形式を使うかはアプリケーションで決める必要がある。 コンテントネゴシエーションのように複数のプロトコルが選択できるように使われる。 このヘッダーはオプション
サーバーレスポンス
HTTP/1.1 101 Switching Protocols // HTTPがUpgrade!! Upgrade: websocket Connection: upgrade Sec-WebSocket-Accept: 7eQChgCtQMnVILefJAO6dK5JwPc= Sec-WebSocket-Protocol: chat
- Sec-WebSocket-Accept Sec-WebSocket-Keyを決まったルールで変換した文字列。 これにより、クライアントはサーバーとの通信確立を検証できる。
- Sec-WebSocket-Protocol クライアントからサブプロトコルのリストを受け取ったときに、その中野一つを選択して返す。 クライアントは送信したプロトコル以外を受け取ったら接続を拒否しなければならない
ランダムな文字列からSec-WebSocket-Acceptの値は特定の文字列を接合した後にSHA1ハッシュを計算し、 それをBASE64エンコードした内容になります。
この後は双方向通信を開始します。
Socket.IO
WebSocketは強力なAPIですが、多くの場合、それをさらに使いやすくするSocket.IOという ライブラリを経由して使う方法に人気がありました。
Socket.IOのメリットは次の3点 - WebSocketが使用できないときは、XMLHttpRequestによるロングポーリングでエミュレーションし、 サーバー側からの送信を実現する機能がある - WebSocketの再接続を自動で行う - クライアントだけではなく、サーバー側で使える実装もあり、クライアントが期待する手順で フォールバックのXMLHttpRequest通信をハンドシェイクしたりできる - ロビー機能
WebSocketが使われ始めた当初は後方互換性を広く維持できるということで、 WebSocketといえばSocket.IOでした。
しかし、現在ではWebSocketが使えないブラウザは殆どありません。 企業内のセキュリティ管理のためのウェブプロキシなど、WebSocketが使えなくなる要因はいくつか ありますが、後方互換性目的で他のライブラリを使う理由はかなり減ってきています。 再接続処理などメリットがゼロではありませんが、今後は直接使われるか、 使うにしてもXMLHttpRequestフォールバックをオフにされることが増えるでしょう。
引用元や参考情報
第3話: Server-Sent Eventsの雑多なメモ 〜 REAL WORLD HTTP第7章より 〜
yagisuke.hatenadiary.com の第3話です。
Server-Sent Events(SSE)
SSEはHTML5の機能のひとつです。 巨大なファイルコンテンツを「少しずつ送信」するHTTP/1.1のChunked形式の通信機能を応用し、 サーバーから任意のタイミングでクライアントにイベント通知できる機能です。
2014年にはGREEさんがすでにバックエンドに採用していました。
http://labs.gree.jp/blog/2014/08/11070/
サーバーから情報を送る方法には、Comet(4章参照)がありました。 クライアントから定期的にリクエストを送ることでサーバー側のイベントを検出する(ポーリング)、 あるいはリクエストを受け取った状態で返事を保留する(ロングポーリング)方法がよく使われていました。
ロングポーリングのフロー
画像: http://kimulla.hatenablog.com/entry/2016/01/17/リアルタイムなwebアプリを実現する方法%28ポーリン
Cometのロングポーリング + Chunked レスポンス
を組み合わせて、
1度のリクエストに対して、サーバーから複数のイベント送信を実現したのがSSEです。
イベントストリームについて
SSEはChunked形式を使っていますが、HTTPの上に別のテキストプロトコルを載せています。 これはイベントストリームと呼ばれ、MIMEタイプはtext/event-streamです。
イベントストリームの例
id: 10 event: ping data: { "time": 2017-09-25T01:27:00+000 } id: 11 data: Message from pySpa data: #eng channel
タグの種類 | 説明 |
---|---|
id | イベントを識別するID。再送処理で使用 |
event | イベント名を設定 |
data | イベントと共におくられるデータ(jsonがよく使われる) |
retry | 再接続の待ち時間のパラメータ(ミリ秒) |
SSEのサンプルソース
// SSE APIは、EventSourceインターフェイスに含まれています。 // イベントを受け取るためにサーバへの接続を開始には、 // イベントを生成するスクリプトのURIを指定する、新たなEventSourceオブジェクトを作成します。 // インスタンスを生成したら、メッセージの受け取りを始めることができます。 const evtSource = new EventSource('ssedemo.php') // このコードはeventフィールドを持たない、サーバからの通知を受信して、 // メッセージのテキストをドキュメントのHTMLにあるリストへ追加します。 evtSource.onmessage = function(event) { const newElement = document.createElement('li') newElement.innerHTML = `message: ${event.data}` eventList.appendChild(newElement) } // addEventListener() を使用して特定のイベントを待ち受けることもできます // 前のコードと似ていますが、eventフィールドに"ping"が設定されたメッセージが // サーバから送られたときに、自動的に呼び出されることが異なります。 // こちらはdataフィールドのJSONをパースして、情報を出力します。 evtSource.addEventListener('ping', function(event) { const newElement = document.createElement('li') const obj = JSON.parse(event.data) newElement.innerHTML = `ping at ${obj.time}` eventList.appendChild(newElement); }, false);
ソース元: https://developer.mozilla.org/ja/docs/Server-sent_events/Using_server-sent_events
注意 - IEが対応していません。polyfillで対応可能。 https://developer.mozilla.org/ja/docs/Server-sent_events/Using_server-sent_events
第2話: Fetch API の雑多なメモ 〜 REAL WORLD HTTP第7章より 〜
yagisuke.hatenadiary.com の第2話です。
Fetch API
Fetch APIはXMLHttpRequestと同様の、サーバーアクセスを行う関数です。特徴としては、 デフォルトで厳格な設定がされており、必要に応じて明示的に解除するという設計となっていることです。
JavaScriptから用いられ以下の特徴を持ちます。 - XMLHttpRequestよりも、オリジンサーバー外へのアクセスなど、CORS(Cross-Origin Resource Sharing)の取り扱いが制御しやすい。 - JavaScriptのモダンな非同期処理の記述法であるPromiseに準拠している - キャッシュを制御できる - リダイレクトを制御できる - リファラーのポリシーを設定できる - Service Worker内から利用できる
注意 - IE対応してない。 http://caniuse.com/#search=fetch - Safariも対応していない? https://developer.mozilla.org/ja/docs/Web/API/Fetch_API
Fetch APIの基本
Fetch APIの使用例
fetch('news.json', { // 1 method: 'GET', // 2 mode: 'cors', credentials: 'include', cache: 'default', headers: { 'Content-Type': 'application/json' } }).then(response => { // 3 return response.json() // 4 }).then(json => { console.log(json) })
基本要素は次の4つ
- XMLHttpRequestのようにオブジェクトを作成するのではなく、fetch()関数を呼び出す
- fetch()関数の第二引数はオプションのオブジェクト(省略可能)
- .then()関数に、サーバーレスポンスが帰ってきた後に呼び出されるコールバックを渡す(Promise)
- .then()に渡すコールバックがさらに時間がかかる処理を行い、それがPromiseを返すときは.then()を連結する
Fetch APIが対応するデータ
上記サンプルではjsonでした。以下のサンプルではstringで受け取ってます。
サンプル: https://codepen.io/osublake/pen/OMRdKq (string型でうけとってる)
メソッド | 型 | 説明 |
---|---|---|
arrayBuffer() | ArrayBuffer | 固定長のバイナリデータ。Typed Arrayを使って読み書き可能 |
blob() | Blob | ファイルコンテンツを表す MIMEタイプ + バイナリデータ。FileReaderを経由してArrayBufferに変換可能 |
formData() | FormData | HTMLフォームと互換の名前とあたいのペア |
json() | Object | JSONを解釈してJavaScriptのオブジェクト、配列などで構成されるオブジェクト |
text() | string | 文字列 |
Fetch APIで利用可能なメソッド
対応 | メソッド一覧 |
---|---|
CORS安全 | GET, HEAD, POST |
禁止メソッド | CONNECT, TRACE, TRACK |
参照: https://triple-underscore.github.io/Fetch-ja.html#methods
Fetch APIのCORSモード
Fetch APIではセキュリティ対策としてCORSをどのレベルまで許容するかを表明できます。 XMLHttpRequestの場合モードは変更できないようです。
設定値 | Fetchデフォルト | XHRデフォルト | 説明 |
---|---|---|---|
cors | ○ | 別のオリジンサーバーへのアクセスを許容する | |
same-origin | 別のオリジンサーバーへのアクセスをエラーにする | ||
no-cors | ○ | CORS接続は無視され空のレスポンスが返る |
他にも、navigate、websocketがあります(HTML用の特別な値)。
参照: https://triple-underscore.github.io/Fetch-ja.html#concept-request-mode
Fetch APIのcredentials
クッキーの制限についてです。 XMLHttpRequestの場合、withCredentialプロパティにtrueを設定するとincludeできたのと同等に、 Fetch APIではcredentialsに設定します。
設定値 | Fetchデフォルト | XHRデフォルト | 説明 |
---|---|---|---|
omit | ○ | クッキーを送信しない | |
same-origin | ○ | 同一のオリジンの場合にのみクッキーを送信する | |
include | クッキーを送信する |
参照: https://triple-underscore.github.io/Fetch-ja.html#concept-request-credentials-mode
Fetch APIにしかできないこと
キャッシュの制御
キャッシュが細かく制御できることが特徴です。
設定値 | デフォルト | 説明 |
---|---|---|
default | ○ | 標準的なブラウザの動作 |
no-store | キャッシュがないものとしてリクエストをする。結果もキャッシュしない | |
reload | キャッシュがないものとしてリクエストをする。ETag等は送らない。キャッシュ可能であれば結果をキャッシュする | |
no-cache | 期限内のキャッシュがあってもHTTPリクエストを送信する。ローカルのキャッシュのETag等も送り、サーバーが304を返したらキャッシュしたコンテンツを使う | |
force-cache | 期限外のキャッシュでもあればそれを利用。なければHTTPリクエストする | |
only-if-cached | 期限外のキャッシュでもあれば利用する。なければエラーにする |
参照: https://triple-underscore.github.io/Fetch-ja.html#concept-request-cache-mode
リダイレクトの制御
設定値 | デフォルト | 説明 |
---|---|---|
follow | ○ | リダイレクトをたどる(最大20リダイレクト) |
manual | リダイレクトをたどらず、リダイレクトがあった旨をつたえる | |
error | ネットワークエラーになる |
注意 - Chrome47からはmanualになった模様。 https://developer.mozilla.org/ja/docs/Web/API/GlobalFetch/fetch - どうやらService Workersのみのお話しっぽい。
Service Worker対応
Fetch APIにできて、XMLHttpRequestにできないことは細々ありますが、 一番大きなものはService Workerへの対応です。 現在、Service Worker内から外部サービスへの接続にはFetch APIしかできないようになっています。
Service Workerに対応したWebサービスはオフライン動作が可能になったり、 通知を扱えるようになったりします。