When I try to upload Image from React Native + Expo app to Azure Blob Storage via Azure Functions (Node.js), image(jpeg) can be saved into the storage but that image cannot be opened correctly.
== ASK ==
・How can I upload image? (Current behavior explained in below troubleshooting steps is unexpected? if so, how can I prevent it and upload image precisely..?)
== Assumption ==
・React Native 0.63.2
・Expo 42.0.4
・Expo-Image-Picker 10.2.3
・Request Route :
React Native + Expo App -> API (Azure Functions (Node.js)) -> Azure Blob Storage
== My Code ==
= React Native + Expo (Client Side)
*I implemented based on below discussion: How can I upload a photo with Expo?
*params : returned value from expo-image-picker after image select
const formData = new FormData();
const imageUri = params.uri;
const dataType = mime.getType(imageUri);
const fileName = imageUri.split("/").pop();
formData.append('image',{
uri: imageUri,
name: "a.jpg",
type: dataType
} as any);
const url = 'xxxxx';
await fetch (url, {
method: 'POST',
headers:{
},
body:formData
})
expo-image-picker side code (pass the value of "result" to the above code.)
const pickImage = async () =>{
console.log("PICKIMAGE CALLED.");
// Access Permission Check
let permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (permissionResult.granted === false) {
alert("Permission to access camera roll is required!");
return;
}
// Image Pickup
try{
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: false,
aspect: [4,3],
quality: 0.5,
base64: true,
});
if (!result.cancelled) {
setImageData(result);
}
} catch(E){
console.log(E);
}
};
= Azure Function (Server Side)
const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
const replace = require('buffer-replace');
// Upload Image
try{
// Parse Blob Data
var multipart = require("parse-multipart");
var bodyBuffer = Buffer.from(req.body);
var boundary = multipart.getBoundary(req.headers['content-type']);
var parts = multipart.Parse(bodyBuffer, boundary);
// Upload Blob to Azure Storage
const {BlobServiceClient} = require("@azure/storage-blob");
const containerName = "ContainerName";
const blobName = parts[0].filename;
const blobServiceClient = BlobServiceClient.fromConnectionString("connection string of storage");
const containerClient = blobServiceClient.getContainerClient(containerName);
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
const uploadBlobResponse = await blockBlobClient.upload(parts[0].data, parts[0].data.length);
context.log("Blob was uploaded successfully. requestId: ", uploadBlobResponse.requestId);
context.done();
== Troubleshootings ==
1, When I checked Azure Function side log, "parts" seems have incorrect binary(hex) data. I mean, before "ff d8" (indicator of jpeg format), unexpected line break "0d 0a" seems added. I doubt this is the reason file cannot be opened precisely.
var parts = multipart.Parse(bodyBuffer, boundary);
2, Based on the result of 1, I also checked same thing from client side (React Native + Expo) with below code, and found unexpected line break "0d 0a" is not there. So wondering why unexpected line break is added while processing at server side.
function base64ToHex(str) {
const raw = atob(str);
let result = '';
for (let i = 0; i < raw.length; i++) {
const hex = raw.charCodeAt(i).toString(16);
result += (hex.length === 2 ? hex : '0' + hex);
}
return result.toUpperCase();
}
console.log(base64ToHex(params.base64));
3: Try Image Upload from Postman.
Request Route : Postman -> API (Azure Functions) -> Azure Blob Storage.
The way to send image is little different from that of React Native + Expo app (Postman: seems add image file (blob?) directly into the formdata, ReactNative: add blob uri, mime etc into formdata), but It succeeded.
Thank you very much for your help!!