こんにちは。今週は、画像アップロードと戦い続けて終わった一週間でした・・
結局正しい解決方法は分かっていないのですが、いくつかの問題に遭遇したので、苦闘の記録を残しておこうと思います。
Contents
前提
- React Native
- Expo
- expo-image-picker(画像の選択)
- Androidエミュレータでテスト
問題1:Network Request Failedエラー
Expo-image-pickerで選択した画像をfetch apiを使ってクラウド上のストレージにアップロードしようとしたところ、Network Request Failedエラーが発生。
const formData = new FormData();
const dataBlob = await fetch(params.uri).then((r)=>r.blob());
formData.append('data', dataBlob);
const url = 'xxx'
await fetch (url,{
method: 'POST',
headers:{
・・・・
},
body:formData
})
Network request failed
Fetch APIのドキュメントをみると、blob (file.input[0])も送れるって書いてるんだけどなぁ・・
https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch
原因と解決方法
調べてみると、Androidエミュレータでこのエラーが出るという議論が結構あった。iOSでテストしてないけど、そのあたりからするに、Androidエミュレータに固有の問題なのかもしれない。
以下の議論を元に、blob自体ではなくimageのURIを送る方法でもいけるらしいことがわかったので、この実装に変更して、Network Request Failedエラーは解消することができた。
https://stackoverflow.com/questions/42521679/how-can-i-upload-a-photo-with-expo
が、すぐに次の問題にぶち当たる。
問題2:アップロードされた画像のフォーマットが正しくない
問題1の解決方法の通り、結局FormDataに以下の形式で画像情報をセットしてアップロードした。
formData.append('image',{
uri:imageUri,
name:"a.jpg",
type:dataType
} as any);
サーバーサイドはこんな感じ。
<Node.js>
// Parse Blob Data
context.log("# step1 : require parse-multipart")
var multipart = require("parse-multipart");
context.log("# step2 : buffer")
var bodyBuffer = Buffer.from(req.body);
//var bodyBuffer = req.body
context.log(bodyBuffer)
context.log("# step3 : boundary")
var boundary = multipart.getBoundary(req.headers['content-type']);
context.log(boundary)
context.log("# step4 : parse")
var parts = multipart.Parse(bodyBuffer, boundary);
context.log(parts)
その後Parseしたデータをストレージに保存・・・
が、ストレージに保存された画像をダウンロードしてきて開こうとすると、”ファイルが壊れているか、”プレビュー”が認識しないフォーマットを使用している可能性があります”とでた。
どこで何がどうなったんだ・・・
原因と解決方法
まず、サーバーサイドでストレージに保存する直前の画像データを表示させてみた。
・・・ん?!data部の16進数表記のバイナリデータがff d8から始まっていない・・!?
こちらの記事が参考になりましたが、JPEGデータの場合、FF D8から始まる決まりがあります。
https://qiita.com/kazuaki0213/items/d3e71fe203b4f1d19abc
が、私のプログラム上は、FF D8の前に、0d 0aがくっついているではありませんか・・・
0d 0aは、改行コード (CR + LF)を示すコードです。
どうやらここに意図せぬ改行コードが入ってしまっていることで画像が正しいフォーマットと見做されていないのでは、という仮説に辿り着きました。
では、次はこの改行コードがどこで埋め込まれているのか?という疑問に当たります。
試しにクライアントアプリ側で、image-pickerで取得した画像の16進数バイナリ情報を出力してみました。
あれ・・・ここでは改行コードは入っていない・・。
ということは、画像データをformdataにセットしてから、サーバサイドでparseするまでのどこかで改行コードが混入しているっぽい・・・。
いろいろとデバッグを頑張りましたが、結果として、混入している箇所は特定に至らず・・
ドンピシャなIssueではないですが、Expo-image-pickerのIssueでAndroidの場合だけ改行コードが入る、といった報告もあったことから、iPhoneでは正常に動くか試してみた。
https://github.com/expo/expo/issues/1522
画像は違いますが、(Androidの場合画像を変えても同じだったのでそこは問題ではないと判断)iPhoneの場合は改行コードが混入していない・・・!
うーん、結局原因がよく分からないですが、Android固有で発生する問題の模様・・・
今回は、iOSでアプリを動かすことが優先だったので、一旦コードの変更は行わず、開発を継続することに。
根本的な原因については、Stack Overflowで聞いてみているので、今後何かアップデートがあれば良いな・・・
この問題に1週間以上費やしてしまったよ・・・辛い・・
同じ問題に対処されている方のヒントになれば幸いです。もし、この記事が少しでもお役に立ちましたら、下のいいねボタンをポチっていただけると励みになります・・!
コメントを残す