Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ajax 再々再入門

C302e84057a922dce0ecbe80207e3fcc?s=47 mu_zaru
November 19, 2020

Ajax 再々再入門

配信動画はこちら
https://www.youtube.com/watch?v=MjVpw95oODU&feature=youtu.be

もし良かったらムーザルちゃんねるのチャンネル登録お願いします!
https://www.youtube.com/channel/UCLPHXwLp90A5R69Eltxo-sg

Twitter でもプログラミングネタをつぶやいているのでフォローお待ちしております。
ムー
https://twitter.com/mu_book
zaru
https://twitter.com/zaru

C302e84057a922dce0ecbe80207e3fcc?s=128

mu_zaru

November 19, 2020
Tweet

Transcript

  1. YouTube Live (2020.11.19 Thur. 21:00~)

  2. 話す人 現役のエンジニア二人 赤貝が好きな CTO と デザイン勉強中のエンジニア @mu_book 最近の仕事は figma で画

    面設計をつくることで す。英語の勉強してる。 ムー zaru @zaru CTO, Love 赤貝, JavaScript, Firebase, Web Components. Twitter フォロー お願いします!
  3. - Ajax について - Ajax を実現する実装例 - CORS・クロスドメインの Ajax 話すこと

  4. Ajaxってなんだろう?

  5. Ajaxとは Asynchronous JavaScript + XML 非同期 に JavaScript 使っていい感じに データ

    取得 and の a じゃない のか… 非同期については async/await の動画を 見てください〜
  6. JavaScriptでデータ取得 click 新しい HTML サーバ 通常のページ遷移 click データ サーバ Ajax

    で UI 書き換え JSがDOM を部分的 に変更 通常は、サーバへリクエストすると HTML 自体が返ってきてブラウザはそれを表示す るためにページ自体を書き換える。 JavaScript の XMLHttpRequest という 機能を使ってサーバにデータをリクエスト し、受け取ったら HTML の中の一部の DOM だけを書き換える。 JSが サーバに リクエス ト
  7. Ajaxの歴史 Jesse James Garrett さんが JavaScript を使って非同期にコン テンツを更新している手法を Ajax を名付けた

    IEが XMLHttpRequest 独自実装 Firefox が互換性ある XMLHttpRequest 実装 Google Map など非同期 コンテンツ更新のサービ スが盛り上がる クロスドメイン対応のLevel2 Ajaxを手軽に扱うFW登場 ネイティブアプリのように リッチで軽快な Web アプ リが盛り上がる XMLからJSONメインへ
  8. Ajaxを実装してみる

  9. XMLHttpRequest <button class="js-ajax" data-id="1">1</button> <button class="js-ajax" data-id="2">2</button> <div id="result"></div> <script>

    const buttons = document.querySelectorAll('.js-ajax'); buttons.forEach((button) => { button.addEventListener('click', (event) => { const id = event.target.dataset.id; const xhr = new XMLHttpRequest(); xhr.addEventListener('load', (res) => { const json = JSON.parse(res.target.responseText); const resultElm = document.getElementById('result'); resultElm.innerText = json.title; }); xhr.open('GET', `api.php?id=${id}`); xhr.send(); }); }); </script> HTML + JS ボタンを押すと XMLHttpRequest を使っ てサーバへリクエストをする。返ってきた JSON を指定の DOM に挿入する。 click データ サーバ
  10. fetch ( async / await ) <button class="js-ajax" data-id="1">1</button> <button

    class="js-ajax" data-id="2">2</button> <div id="result"></div> <script> const buttons = document.querySelectorAll('.js-ajax'); buttons.forEach((button) => { button.addEventListener('click', async (event) => { const id = event.target.dataset.id; const url = `http://0.0.0.0:9000/api.php?id=${id}`; const res = await fetch(url); const json = await res.json(); const resultElm = document.getElementById('result'); resultElm.innerText = json.title; }); }); </script> HTML + JS fetch と await を使えばもっと直感的に気 軽にかける。 ただし IE11 で使えない(polyfill)、アップ ロード時の進行状況が取得できないなど、 完全に置き換え可能ではない点に注意。
  11. Ajaxを実現する手段 const url = `/api.php?id=${id}`; $.ajax({ url, success (json) {

    const resultElm = document.getElementById('result'); resultElm.innerText = json.title; } }); jQuery const url = `/api.php?id=${id}`; const res = await axios.get(url); const resultElm = document.getElementById('result'); resultElm.innerText = res.data.title; axios 今、Ajax 目的で積極的に使うことはない が、XMLHttpRequest をラップしていい 感じに使えるようにされている。 Ajax ライブラリの定番。Promise で返っ てくるので await などが使えて便利。 jQuery と同様に XMLHttpRequest を ラップしているので IE11 も使える。
  12. Ajax 以外のデータ通信 JSONP クロスドメインで JS からデータを取 得するための方法。 XMLHttpRequest Level2 の登場で

    必要なくなった。現代では忘れて良 い技術。むしろ使ったらダメ。 comet ブラウザからのリクエストなしに、 サーバからデータを送信することが できる。チャットなどの半リアルタ イムな挙動が作れる。ただ WebSocket に代替している WebSocket ブラウザと常に接続をし双方向通信 をするプロトコル。HTTP と違い、 都度コネクションを張らずにすみ軽 量にデータのやりとりができる。専 用のサーバが必要だが強力 EventSource ブラウザと常に接続をしサーバから ブラウザにデータを送信できる(双 方向ではない)。標準化され通常の HTTP と同じように扱えるので使い やすい
  13. XML or JSON ? ? click データ サーバ

  14. 昔はXML、今はJSON XML ユーザ定義のタグで構造化できるマーク アップ言語。汎用性が高いが、シンプルな Web アプリケーションでは冗長で取り扱い が難しい側面がある。 JSON JavaScript のオブジェクト表記でかける

    データ既述言語。JavaScript で扱いやす く汎用性も高い。数値・真偽や Null など の型がある。 Ajax で返すデータには HTML を返すパターンもある(Rails など)。 サーバサイドで HTML を組み立てて、ブラウザは受け取ったものを単 純に innerHTML に入れるだけなので楽といえば楽。 HTML
  15. ここまでが普通のAjaxの話 普通じゃ ないって 何?

  16. CORS・クロスドメイン オリジン間リソース共有 Cross-Origin Resource Sharing

  17. クロスドメインのAjaxは難しい a.example.com b.example.com click データ サーバ 別のサーバ からの通信 だから拒否 ❌

    セキュリティの観点から XMLHttpRequest などで、別のド メインに対してのリクエストは成功しない。事前に許可して もらう必要がある。 エラー例 見たこと ある…!
  18. 事前許可の方法 リクエストされるがレスポンスヘッダで、許可するオリジン (リクエスト元ドメイン)を指定することで、クロスドメイン でも Ajax が可能になる。 Access-Control-Allow-Origin: https://a.example.com Response Header

    a.example.com b.example.com click データ サーバ OK! * ワイルドカード指定もできるが、基本は明示的に指定する方が良い。
  19. CORS の Cookie リクエスト先のサーバと Cookie の送受信をするには、サーバ 側から許可してもらう必要がある。 Access-Control-Allow-Credentials: true Response

    Header a.example.com b.example.com click データ サーバ Cookie 送るよ Cookie 送るよ const xhr = new XMLHttpRequest(); xhr.open('GET', url); xhr.withCredentials = true; xhr.send(null); fetch(url, { credentials: 'include' }) Cookie 送信例 JS 側もクレデンシャル情報を送るよと言う指示が必要
  20. これで全部解決…? 指定する だけじゃ ないの?

  21. プリフライトリクエスト

  22. 単純ではないリクエストは拒否される ??? 単純では ない…とは?

  23. 単純と、単純ではない a.example.com b.example.com click データ サーバ GET など は単純なの でOK

    a.example.com b.example.com click データ サーバ これはNG ❌ GET POST PUT DELETE カスタムヘッダ Access-Control-Allow-Origin で許可されたオリジンからの リクエストでも「単純ではない」と判定されたリクエストは 許可されない。 単純 単純ではない
  24. 単純と単純じゃない 単純 単純じゃない HTTP Method GET, POST, HEAD PUT, DELETE

    Request Header (主要だけ抜粋) Accept Accept-Language Content-Language Content-Type ( ↓条件あり ) ←以外のリクエストヘッダが含 まれている Content-Type application/x-www-form-urlencoded multipart/form-data text/plain ←以外のContent-type application/json など ReadableStream OK NG JSON の POST は 単純じゃな くなる
  25. プリフライトリクエスト Preflight Request 単純じゃないのは事前に検証する

  26. リクエスト前に検証をする a.example.com b.example.com click サーバ ❶JSON を POST したい ❷本当に送信して

    いいか確認するね プリフライト リクエスト OK ❸OK だから送信する JSON POST 単純でないと判断された JS からのリクエストは、ブラウザが 自動的にプリフライトと言われる事前検証をして通ってから 送信をするようにしている。 ブラウザ
  27. プリフライトは OPTIONS で送信 OPTIONS プリフライト リクエスト プリフライトリクエストは OPTIONS と言う HTTP

    Method で送信される。サーバはそれに対して許可するメソッドや ヘッダ、オリジンなどをリクエストヘッダで応答する。 • Access-Control-Request-Method • Access-Control-Request-Headers • Origin PATCHは 受け付ける HTTP Method つまり OPTIONS のリクエストに応答できないと Ajax できないし、許可リクエストヘッダ返さないのもダメ ポイント
  28. ??? なんでこんな 面倒くさいこ とやるの〜

  29. なぜプリフライトが必要か サーバ側が想定をしていないリクエストを 受け付けないようにするために事前にチェックをする 理由 ???

  30. 想定していないリクエスト DELETE 例えば Access-Control-Allow-Origin を設定していない状態で DELETE メソッドのリクエストを送信した場合、ブラウザ側では結果 を受け取れないため CORS block

    エラーになる。つまりユーザ視点で 言うとリクエストは失敗しているように見える。 ただし…サーバ側にはリクエストは来ているので処理がされてしまう 可能性がある。 つまり実質リクエストは成立してしまっている。
  31. ???

  32. もし、プリフライトがなかったら DELETE リクエストを受け付けて処理する Access-Control-Allow-Origin は 許可していないレスポンスを返す ブラウザが許可されていないのを受 け取って、JS ではレスポンス処理 できないように制限する

    ❶ Ajax で DELETE メソッドを送信 ❷ ❸ ❹ この時点で 削除される このような副作用が起こる可能性のリクエストを事前に きちんと許可されているかをチェックしておかないと困 るケースがある 理由 ❌
  33. 今回は言及しませんが、クロスドメインの Ajax は CSRF ( クロスサ イトリクエストフォージェリ ) にも関連があります。挙動を理解せ ずに、盲目的に

    Access-Control-Allow-Origin などを付けるのは 避けてください。動いたから良い…は危険です。
  34. 結論: 同じドメインでやろう 念のためですが、同じドメインにすれば CSRF の危険がなくなるわけじゃないです

  35. ありがとうございました! 次回は... 未定! 質問感想など呟いていただけると嬉しいです! - ハッシュタグ #mu_zaru - ツイッター情報 @mu_book

    , @zaru チャンネル登録 Good ボタン お願いします! ムーザルちゃんねる