fetch() doing GET instead of POST on react-native (iOS) - ios

I have the following code in my component:
fetch('https://domain.com/api', {
method: 'POST',
headers: {'Accept': 'application/json', 'Content-Type': 'application/json'},
body: JSON.stringify({
key: 'value'
})
}).
then((response) => {
console.log('Done', response);
});
And every time the request is a GET (checked server logs). I thought it was something to do with CORS (but apparently no such thing in react-native) and ATS (but already turned off by default, plus my domain is HTTPS). I've tried from a browser and from a curl and it worked perfectly, so a priori no issue on server configuration. Any idea what's going on here?
I'm using the latest react-native version.

After further digging, it was definitely an issue with the API + fetch. I was missing a slash at the end of the URL and the API issued a 301, that fetch didn't handle correctly. So I don't know if there is something to fix in the fetch function (and underlying mechanisms) but this fixed my issue :)

When a POST is redirected (in my case from http to https) it gets transformed into a GET. (Don't know why...)

Related

How to get CSRF tokens in a React/Rails App? ActionController::InvalidAuthenticityToken

Before going into more detail about the title, I just want to describe the problem at a basic level. I'm getting the dreaded 422, Unprocessable Entity error (ActionController::InvalidAuthenticityToken) after asynchronous requests in my app. What's the best way to handle this?
Loads of answers will say do:
skip_before_action :verify_authenticity_token
(which is now skip_forgery_protection in Rails 6), and then usually in the comments people get way more upvotes asking about whether or not that's a security risk. There are probably 5 threads like that.
The alternatives to doing this though, is sending the csrf token along with the POST request. So, most answers say make sure to include these headers
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
and also a csrf token like:
'X-CSRF-Token': csrfToken
The issue is getting the csrf token itself. I've tried displaying the contents of the header object with
const getHeaders = () => {
let headers = new window.Headers({
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
})
const csrfToken = document.head.querySelector("[name='csrf-token']")
if (csrfToken) { headers.append('X-CSRF-Token', csrfToken) }
return headers
}
and
let headers = getHeaders();
headers.forEach(function(value, name) {
console.log(name + ": " + value);
});
and that doesn't work. I'm guessing however I'm actually getting the token isn't working. Namely:
document.head.querySelector("[name='csrf-token']")
What's the best way to do this with plain ol' JavaScript, no other libraries? I've tried other suggestions and methods to attempt to get the token but so far all have failed. I'm assuming this lives somewhere on my browser but where? I can see all the data in Redux dev tools so the issue is definitely just this token as opposed to sending the correct data correctly (not to mention skip_forgery_protection completely solves it).
In the mean time sadly skip_forgery_protection works perfectly fine added to my Rails controllers, as security isn't the biggest concern in this stage, but I would rather fix the token issue. Thanks!

Cannot POST with ESP8266 (espruino)

I cannot make post request (get works fine) with espruino.
I've already checked the documentation and it seems pretty equal
here is my code:
let json = JSON.stringify({v:"1"});
let options = {
host: 'https://******,
protocol: 'https',
path: '/api/post/*****',
method: 'POST',
headers:{
"Content-Type":"application/json",
"Content-Length":json.length
}
};
let post = require("http").request(options, function(res){
res.on('data', function(data){
console.log('data: ' + data);
});
res.on('close', function(data){
console.log('Connection closed');
});
});
post.end(json);
The espruino console only return the 'connection closed' console.log.
The node.js server console (hosted on heroku and tested with postman) dont return anything.
Obv the esp8266 is connected to the network
What you're doing looks fine (an HTTP Post example is here), however Espruino doesn't support HTTPS on ESP8266 at the moment (there isn't enough memory on the chips for JS and HTTPS).
So Espruino will be ignoring the https in the URL and going via HTTP. It's possible that your server supports HTTP GET requests, but POST requests have to be made via HTTPS which is why it's not working?
If you did need to use HTTPS with Espruino then there's always the official Espruino WiFi boards, or I believe ESP32 supports it fine too.
you're using a package called "http" and then trying to send a request over https. You should also log out 'data' in the res.close so you can get some errors to work with.

Authorization Token is not being received by Django server from ios - React native

When I do a request using Fetch (in ios) from a react native app with a Django backend, the header Authorization Token is not being received, but the others headers are.
I try using nc -l 8090 just to check out if the app was correctly sending the header and it was there. Also, this just happens in the ios version, the android one works just fine.
At checking the Django backend, the Authorization Token is not being received ( I printed what i got in the authentication.py file )
I put the fetch code here:
let response = fetch('http://xxx.xxx.x.xxx:8000/' + 'users', {
method: 'GET',
headers: {
'content-type': 'application/json',
'x-app-key': xxxxxxxxxx,
'Authorization': 'Token xxxxxxxxxxxxxxxxxxxx'
}
}).then((response) => {...}
The error message that im getting in the response is "403 django standar not valid authentication".
I'm not using OAuth2. Any other information that could provide, please let me know and thank you for any help.
Something weird that I just noticed is that when I use the nc cmd (lc -l 8000), at the port 8000, it has the same behavior. The authorization token is not being received.
I solved my problem added a slash at the end of the URL.
let response = fetch('http://xxx.xxx.x.xxx:8000/' + 'users/', {
method: 'GET',
headers: {
'content-type': 'application/json',
'x-app-key': xxxxxxxxxx,
'Authorization': 'Token xxxxxxxxxxxxxxxxxxxx'
}
}).then((response) => {...}
I had a variation of this issue with a backend using the laravel framework. I finally resolved it by using the following in the .htaccess file of the public folder.
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
Combined with one other important factor in my case, losing the trailing slash from the url in the fetch.
Hope this helps, either way. Good luck.

React-Native fetch API aggressive cache

I'm using fetch API for interacting with server in my react-native#0.28 app, but facing with quite aggressive caching.
Call which I proceed can be expressed like:
fetch(route + '&_t=' + Date.now(), {
headers: {
'Cache-Control': 'no-cache',
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json',
'Custom-Auth-Header': 'secret-token'
},
method: 'POST',
body: data,
cache: 'no-store'
})
In IOS simulator response get cached for 15-20 mins, can be cleared via Reset Content and Settings.
In result I just don't want to have any cache for any of my calls (including GET requests).
I tried all options which I know in order to avoid caching, but seems there is something else, any help would be very appreciated!
It turned out caching was caused by the server setting the session cookie. iOS/Android handles cookies automatically so it was used with every fetch call.
The solution was to delete all the cookies on logout using the https://github.com/joeferraro/react-native-cookies library.

Crossdomain AJAX call to Luracast Restler API: "PUT" and "DELETE" sending "OPTIONS" - Why?

I've installed Luracast's Restler API framework and am having marvelous success with it all except when sending PUT or DELETE across domains. The below works fine when all on the same server, but when I cross domains, Firebug shows the the PUT or GET as OPTIONS, and it is not found on the server. Am baffled how to stop "OPTIONS" being sent instead of PUT or DELETE.
$.ajax({
url: url,
type: 'PUT',
data: "thename="+ $('#TheName').val(),
success: function(xhr, status) {
console.info(xhr);
},
error: function(xhr, status) {
console.info(xhr.responseText);
},
complete: function(xhr, status) {
$('#showResponse').val(xhr.responseText);
}
});
Per another thread somewhere, I've added the below to the Restler output:
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, DELETE, PUT, OPTIONS');
You've got the right response headers, but you have to have your server respond to an OPTIONS request with those headers, too.
This is a cross-origin request, and is subject to something called preflighting. Before making the PUT or DELETE request the browser asks the target web server if it's safe to do so from a web page at another domain. It asks that using the OPTIONS method. Unless the target server says it's okay, the web browser will never make the PUT or DELETE request. It has to preflight the request, because once it's made the PUT or DELETE, it's too late to honor the response; sensitive information may have been leaked.
GET and POST are a bit more complicated, as sometimes the browser decides they are safe without asking first, while other times the browser will also do a preflight check. It depends on whether certain headers are used in the request.
The CORS spec has the gory details. The bottom line is that the code on your web page will not be allowed to make these requests unless the target web server supports the OPTIONS method, and the response to the OPTIONS method includes the headers saying that such requests are allowed.

Resources