“the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded” from superagent in Android React Native
Thanks for everyone's help. With the confirmation that the error isn't likely to be CORS I did some digging with the debugger and found the actual error: Binary FormData part needs a content-type header
From there, I was able to do even more digging, and found that I was being led astray (at least on Android) by the documentation https://visionmedia.github.io/superagent/#attaching-files as the options
map I was sending was being ignored
With the help of the react-native-mime-types
package the fixed code looks like this:
//snip
const fileWithMime = { ...file, type: mime.lookup(name) };
request.post(`${SERVER_URL}/uploads`)
.set('Authorization', cookie)
.withCredentials()
.attach('uri', fileWithMime)
alt
I'm a generalist IT consultant and developer. I try to learn a little about everything!
Updated on June 29, 2022Comments
-
alt almost 2 years
I'm using
superagent
to upload files from my React Native app. It works perfectly fine on iOS, but on Android it gives this error:Possible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc.
I've created a minimal example here https://snack.expo.io/@twohill/upload-example and copied the code below in case the snack goes away:
import React, { Component } from 'react'; import { Text, View, StyleSheet, TouchableOpacity } from 'react-native'; import Constants from 'expo-constants'; import * as DocumentPicker from 'expo-document-picker'; import superagent from 'superagent'; import AssetExample from './components/AssetExample'; import { Card } from 'react-native-paper'; const upload = (file, setMessage) => { const { name } = file; superagent.post('https://example.org/uploads') // <-- change this URL to your server that accepts uploads and is CORS enabled .set('Authorization', 'BEARER xxxyyy') // <-- JWT token here .attach('uri', file, name) .then( result => setMessage(JSON.stringify({result})), error => setMessage(JSON.stringify({error})) ); }; const pickDocuments = async (setMessage) => { const file = await DocumentPicker.getDocumentAsync({ copyToCacheDirectory: true }); if (file.type === "success") { upload(file, setMessage); } } export default class App extends Component { state = { message: null, } render() { const { message } = this.state; return ( <View style={styles.container}> <TouchableOpacity onPress={() => pickDocuments(message => this.setState({message}))}> <Text style={styles.paragraph}> Tap to upload a file </Text> <Card> <AssetExample /> </Card> <Card><Text>{message}</Text></Card> </TouchableOpacity> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', paddingTop: Constants.statusBarHeight, backgroundColor: '#ecf0f1', padding: 8, }, paragraph: { margin: 24, fontSize: 18, fontWeight: 'bold', textAlign: 'center', }, });
If I console.log the error it gives the following:
Request has been terminated Possible causes: the network is offline, Origin is not allowed by Access-Control-Allow-Origin, the page is being unloaded, etc. * http://192.168.1.3:19001/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&minify=false&hot=false:282311:24 in crossDomainError - node_modules\@sentry\utils\dist\instrument.js:224:24 in <anonymous> - node_modules\event-target-shim\dist\event-target-shim.js:818:39 in EventTarget.prototype.dispatchEvent - node_modules\react-native\Libraries\Network\XMLHttpRequest.js:566:23 in setReadyState - node_modules\react-native\Libraries\Network\XMLHttpRequest.js:388:25 in __didCompleteResponse - node_modules\react-native\Libraries\vendor\emitter\EventEmitter.js:190:12 in emit - node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:436:47 in __callFunction - node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:111:26 in __guard$argument_0 - node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:384:10 in __guard - node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:110:17 in __guard$argument_0 * [native code]:null in callFunctionReturnFlushedQueue
As far as I can tell, on Android the app never tries an upload. My server runs
express
and has thecors
middleware enabled with the default configuration{ "origin": "*", "methods": "GET,HEAD,PUT,PATCH,POST,DELETE", "preflightContinue": false, "optionsSuccessStatus": 204 }
Any ideas what to do here? I get the feeling that the Android is baulking at the "*" origin, but have no idea what to put in place for a mobile app.
Or am I barking up the wrong tree completely?
-
alt over 4 yearsI had assumed that CORS wasn't required, however I also serve web clients so it's needed for that. Also I'm not sure if the issue link applies any more - otherwise wouldn't it be broken on iOS as well?