fetch 使ってみる
- カテゴリ:
- JavaScript
- コメント数:
- Comments: 0
◆ Promise が多い
◆ text メソッドでテキストで取得できる
◆ body の ReadableStreamReader は使い方が微妙
◆ デフォルトだと cookie が送られない
◆ text メソッドでテキストで取得できる
◆ body の ReadableStreamReader は使い方が微妙
◆ デフォルトだと cookie が送られない
今日は Promise 調べてたのも実は fetch で使われてたからだったりします
fetch 関数の返り値は Promise です
どんなデータが取れるのか見てみます
プロパティは
などがあります
Headers 型はプロパティにデータはないようです
メソッドを使って
他にも keys, values, entries でイテレータ取得ができます
あとは get, set, has, delete, append があります
set や append があるのでヘッダーですし リクエストの時にも使うみたいです
どれも実行すると Promise が返って来ます
then で受け取ったデータが各種データです
一番良く使うと思うので fetch から全体
catch を忘れずに
ReadableByteStream というものらしいです
cancel と getReader メソッドしかないです
getReader メソッドを実行してみると
ReadableByteStreamReader という型になりました
長い……
データを取り出すと Uint8Array
バイナリデータで取得してるようです
でも 2353 バイトって少なくないような
done が false なのでまだ続きそうです
さらによくみたらこのオブジェクトのフォーマットってイテレータの next メソッドの返り値です
でも next なんてメソッドはないですし 続きの取得方法がわかりません
とりあえず reader の read を複数回やってみる
REPL でやると毎回データが変わっていたので setTimeout で時間差実行してみます
ということは
でも setTimeout って絶対やり方間違ってると思います
何かいい方法があるはず
読み取り可能になったらみたいなものがきっと
Node.js だと on で readable とかイベントつけておけばできたと思うのですが メソッド一覧を見てもないので その方法が使えないみたいです
諦めてぐぐってみたのですが
Streams Standard
それっぽいものはありましたが 書かれてるものが未実装だったりこの仕様自体が未確定なものが多いです
特に ReadableByteStreamReader なんかほとんど TBA です
TBA は To Be Announced の略でまだ決まってないから後で ということだそうです
そのせいでログイン必要なページを開くと ログイン画面の HTML やエラー JSON が返って来ます
cookie のセットもできるとは思いますが ググッて簡単に見当たらなかったのでまたいつか調べます
xhr みたいにデフォルトはそのユーザの cookie 送ってくれればいいのに
fetch
fetch は xhr をもっと楽に使えるものfetch("/test.html")
これだけでその URL のデータが取得できますfetch 関数の返り値は Promise です
どんなデータが取れるのか見てみます
Response
var res = null
fetch("/").then(e => res = e)
res
// Response {}
Response 型のデータが取得できましたfetch("/").then(e => res = e)
res
// Response {}
プロパティは
res.url
// http://var.blog.jp/
res.type
// basic
res.status
// 200
res.statusText
// OK
res.ok
// true
// http://var.blog.jp/
res.type
// basic
res.status
// 200
res.statusText
// OK
res.ok
// true
などがあります
Headers
headers にヘッダーが入っていますres.headers
// Headers {}
// Headers {}
Headers 型はプロパティにデータはないようです
メソッドを使って
res.headers.forEach((value, key) => console.log(key, ": ", value))
// date : Sat, 16 Jan 2016 14:26:55 GMT
// content-encoding : gzip
// vary : User-Agent,Accept-Encoding
// server : Plack::Handler::Starlet
// p3p : CP="BUS OUR PHY STP ADM CUR DEV PSA PSD"
// transfer-encoding : chunked
// content-type : text/html; charset=utf-8
// connection : close
// x-framework : JP/4.01
こうするようです// date : Sat, 16 Jan 2016 14:26:55 GMT
// content-encoding : gzip
// vary : User-Agent,Accept-Encoding
// server : Plack::Handler::Starlet
// p3p : CP="BUS OUR PHY STP ADM CUR DEV PSA PSD"
// transfer-encoding : chunked
// content-type : text/html; charset=utf-8
// connection : close
// x-framework : JP/4.01
他にも keys, values, entries でイテレータ取得ができます
あとは get, set, has, delete, append があります
set や append があるのでヘッダーですし リクエストの時にも使うみたいです
Promise で読みだす系
他には text, json, blob というメソッドがありますres.text
// function text() { [native code] }
res.json
// function json() { [native code] }
res.blob
// function blob() { [native code] }
// function text() { [native code] }
res.json
// function json() { [native code] }
res.blob
// function blob() { [native code] }
どれも実行すると Promise が返って来ます
then で受け取ったデータが各種データです
blob の場合
var blob = res.blob()
// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: Blob}
blob.then(e => console.log(e))
// Blob {}
// size: 76779
// type: "text/html"
// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: Blob}
blob.then(e => console.log(e))
// Blob {}
// size: 76779
// type: "text/html"
text の場合
一番良く使うと思うので fetch から全体
fetch("/").then(e => e.text()).then(e => console.log(e.substr(0, 10)))
// <!doctype
// <!doctype
json の場合
fetch("/")
.then(e => e.json())
.then(e => console.log(e.substr(0, 10)))
.catch(e => console.log("parse error"))
// parse error
.then(e => e.json())
.then(e => console.log(e.substr(0, 10)))
.catch(e => console.log("parse error"))
// parse error
catch を忘れずに
ReadableByteStream
body というプロパティがあったので試してみますres.body
// ReadableByteStream {}
// ReadableByteStream {}
ReadableByteStream というものらしいです
cancel と getReader メソッドしかないです
getReader メソッドを実行してみると
res.body.getReader()
// ReadableByteStreamReader {}
// closed: Promise
// cancel: function cancel()
// read: function read()
// releaseLock: function releaseLock()
// ReadableByteStreamReader {}
// closed: Promise
// cancel: function cancel()
// read: function read()
// releaseLock: function releaseLock()
ReadableByteStreamReader という型になりました
長い……
ReadableByteStreamReader
reader と来たらもう read メソッドを使うしかないですres.body.getReader().read()
// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: Object}
res.body.getReader().read().then(e => console.log(e))
// Object {}
// done: false
// value: Uint8Array[2353]
Promise が返って来ます// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: Object}
res.body.getReader().read().then(e => console.log(e))
// Object {}
// done: false
// value: Uint8Array[2353]
データを取り出すと Uint8Array
バイナリデータで取得してるようです
でも 2353 バイトって少なくないような
done が false なのでまだ続きそうです
さらによくみたらこのオブジェクトのフォーマットってイテレータの next メソッドの返り値です
でも next なんてメソッドはないですし 続きの取得方法がわかりません
とりあえず reader の read を複数回やってみる
fetch("/").then(e => e.body.getReader()).then(reader => {
reader.read().then(e => console.log(e))
reader.read().then(e => console.log(e))
reader.read().then(e => console.log(e))
})
// Object {done: false, value: Uint8Array[2353]}
一回しか表示されてないですreader.read().then(e => console.log(e))
reader.read().then(e => console.log(e))
reader.read().then(e => console.log(e))
})
// Object {done: false, value: Uint8Array[2353]}
REPL でやると毎回データが変わっていたので setTimeout で時間差実行してみます
fetch("/").then(e => e.body.getReader()).then(reader => {
reader.read().then(e => console.log(e))
setTimeout(() => reader.read().then(e => console.log(e)), 1000)
})
// Object {done: false, value: Uint8Array[2563]}
// Object {done: false, value: Uint8Array[4347]}
別のデータが取得できてますreader.read().then(e => console.log(e))
setTimeout(() => reader.read().then(e => console.log(e)), 1000)
})
// Object {done: false, value: Uint8Array[2563]}
// Object {done: false, value: Uint8Array[4347]}
ということは
fetch("/").then(e => e.body.getReader()).then(reader => {
read()
function read(){
reader.read().then(e => {
console.log(e)
e.done || setTimeout(read, 300)
})
}
})
// Object {done: false, value: Uint8Array[2353]}
// Object {done: false, value: Uint8Array[5943]}
// Object {done: false, value: Uint8Array[30151]}
// Object {done: false, value: Uint8Array[23667]}
// Object {done: false, value: Uint8Array[5594]}
// Object {done: false, value: Uint8Array[9071]}
// Object {done: true, value: undefined}
done が true になるまで繰り返して全部取れましたread()
function read(){
reader.read().then(e => {
console.log(e)
e.done || setTimeout(read, 300)
})
}
})
// Object {done: false, value: Uint8Array[2353]}
// Object {done: false, value: Uint8Array[5943]}
// Object {done: false, value: Uint8Array[30151]}
// Object {done: false, value: Uint8Array[23667]}
// Object {done: false, value: Uint8Array[5594]}
// Object {done: false, value: Uint8Array[9071]}
// Object {done: true, value: undefined}
でも setTimeout って絶対やり方間違ってると思います
何かいい方法があるはず
読み取り可能になったらみたいなものがきっと
Node.js だと on で readable とかイベントつけておけばできたと思うのですが メソッド一覧を見てもないので その方法が使えないみたいです
諦めてぐぐってみたのですが
Streams Standard
それっぽいものはありましたが 書かれてるものが未実装だったりこの仕様自体が未確定なものが多いです
特に ReadableByteStreamReader なんかほとんど TBA です
TBA は To Be Announced の略でまだ決まってないから後で ということだそうです
エラーの場合
ところで エラーの場合は status などのプロパティはこうなりましたfetch("/ffffff").then(e => console.log(e))
// Response {}
// body: (...)
// bodyUsed: false
// headers: Headers {}
// ok: false
// status: 404
// statusText: "Not Found"
// type: "basic"
// url: "http://var.blog.jp/ffffff"
// Response {}
// body: (...)
// bodyUsed: false
// headers: Headers {}
// ok: false
// status: 404
// statusText: "Not Found"
// type: "basic"
// url: "http://var.blog.jp/ffffff"
cookie 送れない
普通にテキスト取り出しする分には問題なく使えますが cookie が送信されていないようですそのせいでログイン必要なページを開くと ログイン画面の HTML やエラー JSON が返って来ます
cookie のセットもできるとは思いますが ググッて簡単に見当たらなかったのでまたいつか調べます
xhr みたいにデフォルトはそのユーザの cookie 送ってくれればいいのに