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

Ajax 再々再入門

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

mu_zaru

November 19, 2020
Tweet

More Decks by mu_zaru

Other Decks in Programming

Transcript

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

    View full-size slide

  2. 話す人
    現役のエンジニア二人
    赤貝が好きな CTO と
    デザイン勉強中のエンジニア
    @mu_book
    最近の仕事は figma で画
    面設計をつくることで
    す。英語の勉強してる。
    ムー
    zaru
    @zaru
    CTO, Love 赤貝,
    JavaScript, Firebase,
    Web Components.
    Twitter フォロー
    お願いします!

    View full-size slide

  3. - Ajax について
    - Ajax を実現する実装例
    - CORS・クロスドメインの Ajax
    話すこと

    View full-size slide

  4. Ajaxってなんだろう?

    View full-size slide

  5. Ajaxとは
    Asynchronous JavaScript + XML
    非同期 に JavaScript 使っていい感じに データ 取得
    and の a
    じゃない
    のか…
    非同期については
    async/await の動画を
    見てください〜

    View full-size slide

  6. JavaScriptでデータ取得
    click
    新しい
    HTML
    サーバ
    通常のページ遷移
    click
    データ
    サーバ
    Ajax で UI 書き換え
    JSがDOM
    を部分的
    に変更
    通常は、サーバへリクエストすると HTML
    自体が返ってきてブラウザはそれを表示す
    るためにページ自体を書き換える。
    JavaScript の XMLHttpRequest という
    機能を使ってサーバにデータをリクエスト
    し、受け取ったら HTML の中の一部の
    DOM だけを書き換える。
    JSが
    サーバに
    リクエス

    View full-size slide

  7. Ajaxの歴史
    Jesse James Garrett さんが
    JavaScript を使って非同期にコン
    テンツを更新している手法を Ajax
    を名付けた
    IEが XMLHttpRequest
    独自実装
    Firefox が互換性ある
    XMLHttpRequest 実装
    Google Map など非同期
    コンテンツ更新のサービ
    スが盛り上がる
    クロスドメイン対応のLevel2
    Ajaxを手軽に扱うFW登場
    ネイティブアプリのように
    リッチで軽快な Web アプ
    リが盛り上がる
    XMLからJSONメインへ

    View full-size slide

  8. Ajaxを実装してみる

    View full-size slide

  9. XMLHttpRequest
    1
    2

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

    View full-size slide

  10. fetch ( async / await )
    1
    2

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

    View full-size slide

  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 も使える。

    View full-size slide

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

    View full-size slide

  13. XML or JSON ?

    click
    データ
    サーバ

    View full-size slide

  14. 昔はXML、今はJSON
    XML
    ユーザ定義のタグで構造化できるマーク
    アップ言語。汎用性が高いが、シンプルな
    Web アプリケーションでは冗長で取り扱い
    が難しい側面がある。
    JSON
    JavaScript のオブジェクト表記でかける
    データ既述言語。JavaScript で扱いやす
    く汎用性も高い。数値・真偽や Null など
    の型がある。
    Ajax で返すデータには HTML を返すパターンもある(Rails など)。
    サーバサイドで HTML を組み立てて、ブラウザは受け取ったものを単
    純に innerHTML に入れるだけなので楽といえば楽。
    HTML

    View full-size slide

  15. ここまでが普通のAjaxの話
    普通じゃ
    ないって
    何?

    View full-size slide

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

    View full-size slide

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

    セキュリティの観点から XMLHttpRequest などで、別のド
    メインに対してのリクエストは成功しない。事前に許可して
    もらう必要がある。
    エラー例
    見たこと
    ある…!

    View full-size slide

  18. 事前許可の方法
    リクエストされるがレスポンスヘッダで、許可するオリジン
    (リクエスト元ドメイン)を指定することで、クロスドメイン
    でも Ajax が可能になる。
    Access-Control-Allow-Origin: https://a.example.com
    Response Header
    a.example.com b.example.com
    click
    データ
    サーバ
    OK!
    * ワイルドカード指定もできるが、基本は明示的に指定する方が良い。

    View full-size slide

  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 側もクレデンシャル情報を送るよと言う指示が必要

    View full-size slide

  20. これで全部解決…?
    指定する
    だけじゃ
    ないの?

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  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 で許可されたオリジンからの
    リクエストでも「単純ではない」と判定されたリクエストは
    許可されない。
    単純 単純ではない

    View full-size slide

  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 は
    単純じゃな
    くなる

    View full-size slide

  25. プリフライトリクエスト
    Preflight Request
    単純じゃないのは事前に検証する

    View full-size slide

  26. リクエスト前に検証をする
    a.example.com b.example.com
    click
    サーバ
    ❶JSON を POST したい
    ❷本当に送信して
    いいか確認するね
    プリフライト
    リクエスト
    OK
    ❸OK だから送信する
    JSON POST
    単純でないと判断された JS からのリクエストは、ブラウザが
    自動的にプリフライトと言われる事前検証をして通ってから
    送信をするようにしている。
    ブラウザ

    View full-size slide

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

    View full-size slide

  28. ???
    なんでこんな
    面倒くさいこ
    とやるの〜

    View full-size slide

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

    View full-size slide

  30. 想定していないリクエスト
    DELETE
    例えば Access-Control-Allow-Origin を設定していない状態で
    DELETE メソッドのリクエストを送信した場合、ブラウザ側では結果
    を受け取れないため CORS block エラーになる。つまりユーザ視点で
    言うとリクエストは失敗しているように見える。
    ただし…サーバ側にはリクエストは来ているので処理がされてしまう
    可能性がある。 つまり実質リクエストは成立してしまっている。

    View full-size slide

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

    Ajax で DELETE メソッドを送信



    この時点で
    削除される
    このような副作用が起こる可能性のリクエストを事前に
    きちんと許可されているかをチェックしておかないと困
    るケースがある
    理由

    View full-size slide

  32. 今回は言及しませんが、クロスドメインの Ajax は CSRF ( クロスサ
    イトリクエストフォージェリ ) にも関連があります。挙動を理解せ
    ずに、盲目的に Access-Control-Allow-Origin などを付けるのは
    避けてください。動いたから良い…は危険です。

    View full-size slide

  33. 結論: 同じドメインでやろう
    念のためですが、同じドメインにすれば CSRF の危険がなくなるわけじゃないです

    View full-size slide

  34. ありがとうございました!
    次回は... 未定!
    質問感想など呟いていただけると嬉しいです!
    - ハッシュタグ #mu_zaru
    - ツイッター情報 @mu_book , @zaru チャンネル登録
    Good ボタン
    お願いします!
    ムーザルちゃんねる

    View full-size slide