React Native / Expo : Fetch throws “Network request failed” - api

I saw several posts on the subject but without result. I have on the one hand a form which collects information (name, first name etc) then saves it in database (mongodb). Everything works when I use postman to send my information via the route / signup, i can see my new user in mongodb. but when i'm starting the app on Expo he throw me "Network request failed".
Frontend fetch :
submitForm = () => {
var signupData = JSON.stringify({
first_name: this.state.firstName,
last_name: this.state.lastName,
email: this.state.email,
password: this.state.password
});
fetch(`https://localhost:3000/signup`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: signupData
})
.then(response => {
console.log(response);
return response.json();
})
.then(data => {
if (data.result) {
this.props.handleUserValid(
this.state.firstName,
this.state.lastName,
this.state.email,
data.user.token
);
this.props.navigation.navigate("Account");
}
})
.catch(error => {
console.error(error);
});
};
And Backend route :
router.post("/signup", function(req, res, next) {
var salt = uid2(32);
console.log("Signup is running...");
const newUser = new userModel({
first_name: req.body.first_name,
last_name: req.body.last_name,
email: req.body.email,
password: SHA256(req.body.password + salt).toString(encBase64),
token: uid2(32),
salt: salt
});
newUser.save(function(error, user) {
console.log("LOG: user", user);
res.json({ result: true, user });
});
});
module.exports = router;
And here is a screenshot of the error
Again when using Postman, the fetch is working good, my console log is printed and the user added to my data base.
Thanks for the help.
-- EDIT --
I launched the application in a web browser via Expo and everything works perfectly. My sign in / sign up pages and my account page. But on my phone it's not working (IOS), it's a network problem from my phone (maybe a certificate problem, wrong IP ?)
if you have an idea i'm interested, i've been stuck on it for 2 days

Had the same issue with React-native Expo and Python Django back-end.
The problem is about a conflict between an emulator localhost and server localhost.
Your back-end-server might be ruunning on 127.0.0.1:8000, but an emulator can't find this.
In terminal find your Ipv4-Address with a command 'ipconfig'.
For ex., it will be 192.138.1.40
After this put it into your fetch (
'http://192.138.1.40:8000/').
And what is also important - run your back-end-server with the same host and port.
On python Django for example:
py manage.py runserver 192.138.1.40:8000
On Django you will also need to add ALLOWED_HOSTS = ['192.138.1.40'] in settings.py

Instead of 'localhost', while using expo, use your device's (computer's) IP address (http://192.168.x.x:3000/'signup'). This method worked for me. Make sure that your PC and mobile are connected to the same network. Type ipconfig/all in the command prompt to find IP address.
Update:
Seems like this was my problem coupled with my roommates hogging the wifi bandwidth. Slow internet connection may also be a problem. ATB with your problem.

I had the same issue with Expo: fetch error. For my backend. I use json-server to mock API data. In my case, the json-server runs on http://localhost:3000/playlist
Instead of fetch("http://localhost:3000/playlist"), I did fetch(http://10.0.2.2:3000/playlist), then it worked. Using the Android emulator, it could not find the server's address.
For the reason why using 10.0.2.2, check here. why do we use 10.0.2.2 to connect to local web server instead of using computer ip address in android client

I had the same issue - what worked for me was to:
Run my local server on host 0.0.0.0
Go to network preferences and find my LAN IP address (e.g. 192.168.1.1)
Replace the host in my url in the mobile app with the LAN IP (e.g. http://192.168.1.1:3000/signup)
Reload and test
For anyone using Serverless, I used this command to run on 0.0.0.0
ENV=local serverless offline -s local -o 0.0.0.0

I had a similar issue. Apparently, the emulator does not understand or see 'localhost' as host.
What I did:
run ipconfig on your cmd, copy the ipv4 address, then use that to replace 'localhost' for your server host.

you should check the URL
https://localhost:3000/signup (X)
http://localhost:3000/signup (O)
NOT HTTPS

If anyone facing this issue with a hosted backend server this is for your knowledge.
Used react native expo cli
Backend(Spring Boot) hosted on a Azure server ( Eg URL : https://abcd-spring-app.azurewebsites.net). HTTPS used.
But still I faced the below issue.
Network request failed at node_modules\whatwg-fetch\dist\fetch.umd.js:535:17 in setTimeout$argument_0
at node_modules\react-native\Libraries\Core\Timers\JSTimers.js:130:14 in _callTimer
at node_modules\react-native\Libraries\Core\Timers\JSTimers.js:383:16 in callTimers
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:416:4 in __callFunction
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:109:6 in __guard$argument_0
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:364:10 in __guard
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:108:4 in callFunctionReturnFlushedQueue
After some research I found that this is because the slow response time of the server. The network request failed due to the timeout.
So Before testing your app with the backend server, send some requests from the web(or any other way) and up your server. Because some servers get inactive after some time. Make sure you have a good connection.

Related

Connect to remote Express API from Postman

I am trying to connect to my API, hosted on a remote VPS, via Postman but can't seem to find any definitive guides on how to do it.
The VPS has a frontend app (Vue) that connects to Express using Nginx reverse proxy. That works fine.
However, I want to share some of the Express API with another client not hosted on the same server. For example, connecting from Postman with user authentication to just share data in JSON format.
If anyone can give me any advice on how to achieve this I would much appreciate it.
EDIT
Here is an example request I am trying from Postman. Express is confirmed running on 3001 on the VPS.
http://vps-url:3001/test
This is the corresponding route in Express
app.get("/test", (req,res)=>{
res.json({ msg: 'Hello from VPS!' })
})
When I try to access in Postman, is just hangs.
I have also this CORS config to allow connection from my local machine using my public IP.
app.use((req, res, next) => {
const corsWhitelist = [
'http://vps-url.com',
'https://anotherclient',
'70.80.xxx.xxx' // my machine IP
];
if (corsWhitelist.indexOf(req.headers.origin) !== -1) {
res.header('Access-Control-Allow-Origin', req.headers.origin);
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
}
next();
});

Network request failed react native 0.64.0 on https live server but in postman api working fine

const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
"username": "mukesh",
"password": "1234"
})
};
var url = 'http://ewayswork.com:9000/customer/'
fetch(url, requestOptions)
.then(response => response.json())
.then(data => {
console.log(data)
})
.catch(function(error) {
console.log('Problem with your fetch operation: ' + error.message);
});
Here is a possibility.
As you are using react-native, you must be using either an emulator or a real device to check your app.
On both of these, you cannot access your API if you are using localhost. instead you need to run the server on your local ip adress.
To get that, go to settings >> network >> wifi >> your_connected_wifi. On the bottom , copy the ipv4 address.
Then, run the server on that ipadress and also change your url accordingly.
E.g,
If your are using django_rest_framework, to run the server on your local ip adress;
python manage.py runserver <Your ip address>
Open Cmd and type: ipconfig , Check if the ipv4 is the same ip you are putting in your url (don't use localhost , use your ip instead) .

Getting 401 unauthorized for Laravel sanctum

I am using Laravel Sanctum with Vuejs SPA. Both reside on same top level domain
Laravel backend : app.demo.localhost
Vue SPA : app-spa.demo.localhost
Login and logout (endpoints) are working correctly when called from VueJS SPA using axios and XSRF-TOKEN is succesfully set, but when I call other api end points it gives me 401 unauthorized.
In axios this is being set
axios.defaults.withCredentials = true;
I have the below configurations
In Laravel .env
SESSION_DRIVER=cookie
SESSION_DOMAIN=.demo.localhost
SANCTUM_STATEFUL_DOMAINS=app-spa.demo.localhost
In Routes/Api.php
Route::middleware('auth:sanctum')->get('api/user', function (Request $request) {
return $request->user();
});
In cors.php
'paths' => ['api/*', 'sanctum/csrf-cookie', 'login', 'logout'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
Could someone help me out please?
If you are using php artisan serve add the port number to SANCTUM_STATEFUL_DOMAINS. So if your port number is 8000:
SESSION_DRIVER=cookie
SESSION_DOMAIN=.demo.localhost
SANCTUM_STATEFUL_DOMAINS=app-spa.demo.localhost:8000
Your SANCTUM_STATEFUL_DOMAINS must match the url in your browser. The port number should not be on the SESSION_DOMAIN.
Following are the 8 steps that I follow while setting up Laravel sanctum check if you missed anything
Step1 composer require laravel/sanctum
Step2 php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider
Step3 php artisan migrate (you can ignore this if you're using spa)
Step4 uncomment this line from app/http/kernel.php \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
Step5 In config/cors.php update 'supports_credentials' => true,
Step6 In .env file update SESSION_DRIVER=cookie & add new line of SESSION_DOMAIN=localhost (even if your using any port like 8080 just mention localhost in session_domain)
Step7 In config/sanctum.php add your client domain along with port(if local) in stateful as follows, in my case for vue CLI it's usually localhost:8080 & for nuxt its localhost:3000 , code is as follows
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:8000,localhost:8080,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))),
Mostly if your stateful (step7) is not setup properly you will get 401 unauthorized or it will try to redirect you to the home page along with cors policy error
Step8 Do not forget to await until sanctum/csrf-cookie promise is resolved
async login() {
await axios.get("http://localhost:8000/sanctum/csrf-cookie");
await axios.post("http://localhost:8000/login", {
email: "kunal#gmail.com",
password: "password",
});
let response = await axios.get("http://localhost:8000/api/user");
console.log(response.data);
},
For anyone dealing with localhost:
SESSION_DRIVER=cookie
SESSION_DOMAIN=localhost
SANCTUM_STATEFUL_DOMAINS=localhost:8080(port number you use)
I just encountered the same problem. I configured all the options according to the official documentation, but I couldn't get the authorization.
Then I use routes/web.php instead of routes/api.php, so I can use sanctum middleware very well.
Now the problem seems obvious,Axios withCredentials maybe need to place in the correct way.
const http = axios.create({
baseURL: API_URL,
withCredentials: true
})
maybe not work. So I add {withCredentials: true} like
http.get('/api/whoami', {withCredentials: true})
.then(res => {
console.log(res.data)
})
Then it works.
But the very strange thing is that it is normal now, no matter whether I clear the browser cache, cookies or Laravel's various caches, there is no previous situation
For me i just had to place the host with port number:
SANCTUM_STATEFUL_DOMAINS=127.0.0.1:5173
and it started working.
Maybe this helps someone.
My problema was.... (no read with attention)
If your SPA needs to authenticate with private / presence broadcast channels, you should place the Broadcast::routes method call within your routes/api.php file:
Hi i found a solution.
My SPA is Vue v3 working on 3000 port.
Also my backend is working on 80 port. (laravel 8.1)
Make Stateful Domains in config/sanctum.php like that
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost:3000',
env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))),
Adding only one and correct domain on their, worked for me magically. I wrote before there whole possible variant of ports, it made me crazy and cost a couple days and nights.
My issue was I setup the domain in the wrong place.
I thought was an array of domains, in config/sanctum.php, but not, needs to be placed within the string:
OK:
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1,myownlocaldomain.test,myownlocaldomain.test:8080', <-------- OK
env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))),
BAD:
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
'%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : '',
'myownlocaldomain.test', <----- BAD
'myownlocaldomain.test:8080', <---- BAD
))),
I hope I save days of work to someone else...

Why is XHR request pending forever on live server?

So i have a react app which if someone is logged in will check for it's account level and based on that will enable or disable features. It worked until it was all localhost, but now i have a server in the cloud and the request is pending forever. Other requests to the same endpoint works fine. I tried changing the address to localhost, but then it looks for the API server on my PC. It's strange because the same endpoint works with other requests. This single request also works on localhost but not if i use server's IP. Here's an image of the Network page of Chrome development tools: https://i.ibb.co/c2r8Js1/Screenshot-at-2019-12-27-15-11-41.png
getLoggedLevel = () => {
var URL = process.env.REACT_APP_API_URL;
var URL2 = 'http://localhost:8000/requests'
axios({
url: URL,
method: 'post',
data: {
message: 'getLoggedLevel',
username: JSON.parse(localStorage.getItem('loggedUser')).username
}
}).then(res => {
this.setState({loggedLevel: res.data.level})
})
}
Edit: I created a separate endpoint for that single request, and it's 404 however in firefox it's 200 for OPTIONS... Now i'm really confused :(

Network error with axios and react native

I have created an API endpoint using the Django python framework that I host externally. I can access my endpoint from a browser (mydomain.com/endpoint/) and verify that there is no error. The same is true when I run my test django server on locally on my development machine (localhost:8000/endpoint/). When I use my localhost as an endpoint, my json data comes through without issue. When I use my production domain, axios gets caught up with a network error, and there is not much context that it gives... from the debug console I get this:
Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:87)
at XMLHttpRequest.dispatchEvent (event-target.js:172)
at XMLHttpRequest.setReadyState (XMLHttpRequest.js:554)
at XMLHttpRequest.__didCompleteResponse (XMLHttpRequest.js:387)
at XMLHttpRequest.js:493
at RCTDeviceEventEmitter.emit (EventEmitter.js:181)
at MessageQueue.__callFunction (MessageQueue.js:353)
at MessageQueue.js:118
at MessageQueue.__guardSafe (MessageQueue.js:316)
This is my axios call in my react native component:
componentDidMount() {
axios.get('mydomain.com/get/').then(response => { // localhost:8000/get works
this.setState({foo:response.data});
}).catch(error => {
console.log(error);
});
}
If you are trying to call localhost on android simulator created with AVD, replacing localhost with 10.0.2.2 solved the issue for me.
It seems that unencrypted network requests are blocked by default in iOS, i.e. https will work, http will not.
From the docs:
By default, iOS will block any request that's not encrypted using SSL.
If you need to fetch from a cleartext URL (one that begins with http)
you will first need to add an App Transport Security exception.
change from localhost to your ip(192.168.43.49)
add http://
http://192.168.43.49:3000/user/
If you do not find your answer in other posts
In my case, I use Rails for the backend and I tried to make requests to http://localhost:3000 using Axios but every time I got Network Error as a response. Then I found out that I need to make a request to http://10.0.2.2:3000 in the case of the android simulator. For the iOS simulator, it works fine with http://localhost:3000.
Conclusion
use
http://10.0.2.2:3000
instead of
http://localhost:3000
update
might worth trying
adb reverse tcp:3000 tcp:3000
For me, the issue was because my Remote URL was incorrect.
If you have the URL is a .env file, please crosscheck the naming and also ensure
that it's prefixed with REACT_APP_ as react might not be able to find it if named otherwise.
In the .env file Something like REACT_APP_BACKEND_API_URL=https://appurl/api
can be accessed as const { REACT_APP_BACKEND_API_URL } = process.env;
Try
"Content-Type": "application/x-www-form-urlencoded",
Accept: "application/json"
If you are using android then open your command prompt and type ipconfig. Then get your ip address and replce it with localhost.
In my case, first I used http://localhost:8080/api/admin/1. Then I changed it to http://192.168.1.10:8080/api/admin/1. It worked for me.
Make sure to change localhost to your_ip_address which you can find by typing ipconfig in Command Prompt
Trying adding to your AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
I was facing the same issue.
i looked deeper and my
endpoint url was not correct.
By giving axios right exact url, my api worked like charm.
Hope it may help anyone
Above mentioned answers only works if you are using localhost but if your code is hosted on a server and Axios throwing Network Error then you can solve this by adding one line.
const config = {
method: 'post',
url: `${BASE_URL}/login`,
headers: {
'Content-Type': 'multipart/form-data'. <----- Add this line in your axios header
},
data : formData
};
axios(config).then((res)=> console.log(res))
I'm using apisauce dependancy & Adding header work for me with React Native Android.
Attach header with request like below:
import { create } from 'apisauce';
const api = create({
baseURL: {baseUrl},
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
}
});
export async function empLogin(data) {
try {
const response = api.post('Login', data);
return await response;
} catch (error) {
console.log(error);
return [];
}
}
before:
axios.get("http://localhost:3456/apt")
.then(
response => {
alert(JSON.stringify(response));
....
}
)
.catch(function(error) {
alert(error.message);
console.warn(error.response._response);
});
I get Error "Network error" Failed to connect to the localhost after that, I make some steps to resolved the error.
Network Error related to axios resloved by the disabling the system firewall and access from the system IP Address like
axios.get("http://192.168.12.10:3456/apt")
.then(
response => {
alert(JSON.stringify(response));
....
}
)
.catch(function(error) {
alert(error.message);
console.warn(error.response._response);
});
For me adding "Accept" in headers resolved the problem:
Accept: 'application/json'