LoginSignup
34
33

More than 5 years have passed since last update.

ServiceWorkerでモックサーバーを作る

Posted at

実験環境は Chrome Canary 43.0.2314.0 だけど動かしてる分は現時点の安定版(40)でも動くはず

やりたいこと

http://localhost:3000/api/* へのリクエストを全部serviceworkerに任せたい。

先行実装として Jxck/response-injection がある。

やり方

sw.js(になるsw.coffee)

console.log 'worker started'
self.onfetch = (event) ->
  console.log 'onfetch', event.request.url
  if event.request.url.indexOf(location.origin+'/api') > -1
    event.respondWith new Response '{"foo": "bar"}',
      status: 200
      headers:
        'Content-Type': 'application/json'

今回は location.origin+'/api', つまり http://localhost:3000/api 以下ならJSONを返却する。それ以外はスルーしてくれる(スルーする為の正しい定義がよくわからん。respondWithしなかったらデフォルトの挙動にフォールバックした)

ServiceWorkerのよくあるサンプルならCacheAPIを使ってアセットをキャッシュするんだけど、今回はどうでもいい。

browserで実行する側

window.addEventListener 'load', =>
  navigator.serviceWorker.register 'sw.js', scope: '.'
  .then (r) ->
    console.log('service-worker registered')
    xhr = new XMLHttpRequest()
    xhr.open 'GET', 'api/foo'
    xhr.responseType = 'json'
    xhr.addEventListener 'load', (data) ->
      console.log 'loaded', data.target.response
    xhr.send()

  .catch (err) ->
    console.error('fail to register', err)

(どうも一回は失敗する。二回目以降有効? navigator.serviceWorker.ready が promiseなのでthenを仕込んでみたけどダメだった。誰か解決策教えてください)

余計な要素が介入してこないように生のxhrでやった。(ここでfetch APIがあったらなぁ)

ハマった点

最初、scope: 'api/' と書いてたら / からのアクセスがonfetchに飛ばず、URL直接踏むとJSON帰ってくる、みたいな挙動で悩んでいたんだけど、次の記事をみて気づいた

Service worker が拓く mobile web の新しいかたち

serviceworkerは自分自身の属するドメインしか扱えないので、 / から /api/ のservice-workerを登録することはできても(なのでURL直接踏むと動く)、 / からの xhr は /api/ 以下に登録された service-workerに対して働かない!!

ということで3時間ぐらい悩みました。Twitterで質問に答えてくれた、ChromiumでServiceWorker実装している @nhiroki_ さんありがとうございます…

34
33
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
33