Hello fellow programmers,
I am trying to show an image using the UserAvatar component in React-Native (Expo) but I am facing a problem where the link I am getting from the API is not working 404 Not Found, what is the best possible way to avoid this problem. I tried to create a blob using the URL of the image but it was not successful
This is the error message i am getting in the app
Online fetched source is not a supported image at node_modules/react-native-user-avatar/src/helpers.js:41:6 in fetchImage
Here is one of the solutions i have tried:
urlToBlob = (url) => new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onerror = reject;
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
resolve(xhr.response);
}
};
xhr.open('GET', url);
xhr.responseType = 'blob'; // convert type
xhr.send();
})this.urlToBlob(data)
.then((blob) => {
console.log(blob);
});
The approach that i took to solve this problem is very simple.
axios
.get(image_url)
.then((res) => {
if (res.status === 200) {
setImageStatus(200);
}
})
.catch((err) => {
setImageStatus(err.response.status);
});
}
When the response status is 200 then the image exists if not fallback to the default image.
Related
I am using xhr to upload images and videos in a React Native mobile app (currently only tested on Android).
The actual upload works correctly however the xhr.upload.onprogress callback is reporting inaccurate data. For example, when uploading a large file (~70mb) this returns 0%, then 69%, then 98%, then 100% - this is returned over the first few seconds even though the actual file upload takes ~1-2 minutes.
Here is my code:
const formData = new FormData();
formData.append("FileInput", {
uri: uri,
type: "video/" + ext,
name: fileName,
});
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.onload = () => {
const response = JSON.parse(xhr.response);
resolve(true);
};
xhr.onerror = (e) => {
console.log(e, "upload failed");
};
xhr.ontimeout = (e) => {
console.log(e, "upload timeout");
};
xhr.send(formData);
if (xhr.upload) {
xhr.upload.onprogress = ({ total, loaded }) => {
uploadProgress = Math.round((loaded / total) * 100);
console.log(uploadProgress, total, loaded);
};
}
Any pointers to what might be going on here would be really appreciated.
UPDATE: I have also implemented this upload using axios and get exactly the same issue where the onUploadProgress reports 100% very quickly even though the actual upload takes much longer.
const config = {
onUploadProgress: (progressEvent) => {
uploadProgress = Math.round(progressEvent.loaded / progressEvent.total) * 100;
console.log(uploadProgress);
},
headers: { "Content-Type": "multipart/form-data" },
};
const upload = await axios.post(url, formData, config);
Ok, I've figured this out. Just in case this helps someone else:
The issue was occurring when running a development bundle on a metro server - axios/xhr was reporting on the status of the upload of the file to the metro proxy rather than to it's final destination on the net.
When I created an apk build everything was working correctly.
Hi i was using NextJs and trying to display pdf file within the web, i was using react-pdf for the package. When using
<Document
file={"http://example.com/sample.pdf"}
onSourceError={(err) => console.log('source err', err)}
onLoadError={err => console.log('load err', err)}
>
<Page
pageNumber={pageNumber}
width={width}
/>
i was having a CORS problem, so i was trying to solve it using NextJs API Routes
api/pdf.js
const request = require('request');
export default (req, res) => {
return new Promise(resolve => {
res.statusCode = 200
res.setHeader('Content-Length', 99999);
res.setHeader('Content-Type', 'application/pdf')
res.setHeader('Content-Disposition', 'attachment; filename=quote.pdf');
let { parentid } = req.headers;
switch (true) {
case req.method === 'GET':
console.log('GET')
request.get('http://example.com/sample.pdf', {}, function (err, response, body) {
if (err) {
console.log('err', err)
res.status(500).json({ code: 'Internal Server Error' })
resolve();
} else {
res.status(200).send(body)
resolve()
}
})
break;
default:
res.status(400).json({ code: 'MethodNotAllowed' })
break;
}
})
}
I tried it in insomnia and i do get a pdf response, but the file is blank,
Does anybody know how to solve this? or there any other options than this? Thanks
react-pdf displays the pages as images. So, you have to add the domain example.com to Next image config as mentioned in https://nextjs.org/docs/basic-features/image-optimization#domains
i have been looking for a solution to convert Image from base64 string into Blob
i get my images via react-native-image-crop-picker
the image object i get is formatted in this way :
{
creationDate: "1299975445"
cropRect: null
data: "/9j...AA"
duration: null
exif: null
filename: "IMG_0001.JPG"
height: 2848
localIdentifier: "10...001"
mime: "image/jpeg"
modificationDate: "1441224147"
path: "/Users/...351F66445.jpg"
size: 1896240
sourceURL: "file:///Users/...IMG_0001.JPG"
width: 4288
}
which means i have the path and source url and image data as base64 string.
what i need is to upload the images that the user picks as blob file to the server.
so is there any way to do the conversion in react native.
ps: i have tried solutions i found online but non of them seems to work so far but none of them seems to work for me.
urlToBlob = (url) => new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onerror = reject;
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
resolve(xhr.response);
}
};
xhr.open('GET', url);
xhr.responseType = 'blob'; // convert type
xhr.send();
})
this.urlToBlob(data)
.then((blob) => {
console.log(blob);
});
i tried this peace of code and this what i got in my console :
{
_data:
blobId: "B69744A5-B8D7-4E6B-8D15-1C95069737EA"
name: "Unknown"
offset: 0
size: 1896240
type: "image/jpeg"
__collector: null
}
after a lot of search i found a solution if anyone faced this issue.
i used a package 'extract-files' it allowed me to the images as files in order to send them to the server
it worked like this:
import { ReactNativeFile } from 'extract-files';
const FormData = require('form-data');
_addImage = async () => {
const { images } = this.state;
if (images.imageData.length > 0) {
const formData = new FormData();
// converting images to files
images.imageData.forEach((element) => {
const file = new ReactNativeFile({
uri: element.sourceURL,
name: element.filename,
type: element.mime,
});
formData.append('files', file);
});
// sending files to the server
await addImages(formData).then((response) => {
console.log('response : ', response);
if (response.success) {
this.pictures = response.filesNames;
this.setState({
isLoading: true,
pictures: response.filesNames
});
return response.success;
}
}).catch((err) => {
console.error(err);
});
}
}
i hope this is helpful
My Question is similar to this which doesn't have an answer. I tried to search many other places but still don't have an answer.
I'm trying to download file using Axios in VueJs as a blob:
return new Promise((resolve, reject) => {
Axios.get(`${fileDownloadUrl}`,
{ responseType: 'blob' } // Blob doesn't handle errors
).then(response => {
let byteData = response.data
var blob = new Blob([byteData], {type: response.headers['content-type']})
let fileName = _.split(response.headers['content-disposition'], '=')
FileSaver.saveAs(blob, fileName[1])
resolve(fileName[1])
},
error => {
console.log(error.response.data) // returns Blob - error message from service is not handled
reject(error.response.data)
}
)
I removed the { responseType: 'blob' } from the above code and tried again, I get the error message now but the file downloaded doesn't have any content, it's a blank data.
How do I download the file and handle the error response returned by the service?
Using vue-resource solved this issue. Although it will be retiring in future releases, I couldn't find a better way to do it as Axios was not able to handle it.
Following is the code:
main.js
import VueResource from 'vue-resource'
Vue.use(VueResource)
service.js
return new Promise((resolve, reject) => {
VueResource.http.get(`${fileDownloadUrl}`,
{ responseType: 'blob' }
).then(response => {
methods.downloadFile(response, cid)
resolve(cid)
}, error => {
reject(error)
})
})
Hope this helps.
import axios from "axios";
// It is needed to handle when your response is not Blob (for example when response is json format)
axios.interceptors.response.use(
response => {
return response;
},
error => {
if (
error.request.responseType === 'blob' &&
error.response.data instanceof Blob &&
error.response.data.type &&
error.response.data.type.toLowerCase().indexOf('json') != -1
) {
return new Promise((resolve, reject) => {
let reader = new FileReader();
reader.onload = () => {
error.response.data = JSON.parse(reader.result);
resolve(Promise.reject(error));
};
reader.onerror = () => {
reject(error);
};
reader.readAsText(error.response.data);
});
}
return Promise.reject(error);
}
);
// Now you can get response in both Blob and json format
axios.get(
url,
{
responseType: 'blob'
}
).then(response => {
// Your Code
}).catch((error) => {
// Your Code
// You can get error in json format
});
May I know is it possible to use post instead of get in the following request
Axios.get(${fileDownloadUrl},
{ responseType: 'blob' }
I am trying to upload image from my react native app to graphql by using Apollo client with createUploadLink(). When I am trying to mutate data by passing a ReactNativeFile as a variable, then it says
"network request failed: Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'. at new ApolloError ".
This this the mutation which i am trying to use
mutation publishPost(
$content: String!
$LocationInput: LocationInput!
$InputPostAttachment: [InputPostAttachment!]
) {
publishPost(
content: $content
location: $LocationInput
attachments: $InputPostAttachment
) {
content
}
}
InputPostAttachment has type
type InputPostAttachment {
type: PostAttachmentType!
file: Upload!
}
Apollo client settings and i am using apollo-upload-client
const httpLink = createUploadLink({
uri: 'http://localhost:8000/graphql',
});
const authLink = setContext(async (headers: any) => {
const token = await getToken();
return {
...headers,
headers: {
authorization: token ? `Bearer ${token}` : null,
},
};
});
const link = authLink.concat(httpLink);
// create an inmemory cache instance for caching graphql data
const cache = new InMemoryCache();
// instantiate apollo client with apollo link instance and cache instance
export const client = new ApolloClient({
link,
cache,
});
File upload Function and i am using react-native-image-crop-picker for multi image selection
const [image, setimage] = useState([]);
const _pickImage = () => {
ImagePicker.openPicker({
includeBase64: true,
multiple: true,
}).then((images: any) => {
let imageData: any = [];
images.map((data: any) => {
const file = new ReactNativeFile({
uri: data.path,
name: data.filename,
type: data.mime,
});
imageData.push({
type: 'IMAGE',
file: file,
});
});
setimage(imageData);
console.log(images);
});
};
const handlePost = async () => {
const InputPostAttachment: any = [...image];
const LocationInput = {
place: place,
vicinity: vicinity,
province: province,
};
publishPost({variables: {content, LocationInput, InputPostAttachment}})
.then(({data}) => {
console.log(data);
props.navigation.navigate('Home');
})
.catch((err) => {
console.log('err happened');
console.log(err);
});
};
could someone please help me out from this?
In addition to the chrome debugger issue, this error also happens on the expo web.
To anyone uploading images on expo web (or react-native web), here's a working solution:
/** Load image from camera/roll. */
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
quality: 1,
});
if (result.cancelled) {
return;
}
/** web platform: blob. */
const convertBase64ToBlob = async (base64) => {
const response = await fetch(base64);
const blob = await response.blob();
return blob;
};
/** android/ios platform: ReactNativeFile.*/
const createReactNativeFile = (uri) => {
const file = new ReactNativeFile({
uri,
type: mime.lookup(uri) || 'image',
name: `file-${Date.now()}`,
});
return file;
};
/** Use blob for web, ReactNativeFile otherwise. */
const file = Platform.OS === 'web'
? await convertBase64ToBlob(result.uri)
: createReactNativeFile(result.uri);
/** Upload image with apollo. */
mutate({ variables: { file } });
On the web platform, ImagePicker returns a base64 value instead of a file path. This problem doesn't happen if the platform is Android or iOS, as ImagePicker returns a file path, which is expected by apollo-upload-client.
The solution is to detect if the URI is base64 (which happens when the platform is "web") and convert it to a blob.
My apollo-client was configured using apollo-boost and i was using chrome debugger to intercept the network was causing me this issue.
To be more specific I was using the below code to get the network requests sent by my app in the chrome debugger
global.XMLHttpRequest =
global.originalXMLHttpRequest || global.XMLHttpRequest;
global.FormData = global.originalFormData || global.FormData;
if (window.FETCH_SUPPORT) {
window.FETCH_SUPPORT.blob = false;
} else {
global.Blob = global.originalBlob || global.Blob;
global.FileReader = global.originalFileReader || global.FileReader;
}
apollo-upload-client wont send the data in multipart data if we are using chrome debugger. We will face network issue.This issue has the answer. or I had not removed apollo-boost and some part of my app was using it that was also a issue.