Fetch: post json data, application/json change to text/plain - javascript

I'm using chrome 53.0.2785.116 m (64-bit).
I got the following headers on devtools. The problem is marked with a "//" comment. content type is really not allowing us to set it to application/json, I have tried a 100 different ways.
import fetch from 'isomorphic-fetch';
const option = {
method: 'POST',
mode: 'no-cors',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({'aa':'bb'})
}
fetch('/books', opts)
.then(check401)
.then(check404)
.then(jsonParse)
.then(errorMessageParse);
Request Headers
accept:application/json
Accept-Encoding:gzip, deflate
Accept-Language:zh-CN,zh;q=0.8
Connection:keep-alive
Content-Length:97
content-type:text/plain;charset=UTF-8 //What happen?
Host:127.0.0.1:8989
Origin:http://127.0.0.1:8989
Referer:http://127.0.0.1:8989/
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36

The problem is that when you work in 'mode' 'no-cors', the Headers become an immutable and you will not be able to change some of its entries. One of the heads you can't change is the Content-Type. When you set 'mode' to 'no-cors' you will be able to change only these headers:
Accept
Accept-Language
Content-Language
Content-Type and whose value, once parsed, has a MIME type (ignoring parameters) that is application/x-www-form-urlencoded, multipart/form-data, or text/plain
In another words, in 'mode' '-no-'cors' you can only set application/x-www-form-urlencoded, multipart/form-data, or text/plain to the Content-Type.
So the solution is stop using fetch or changing it to 'cors' 'mode'. Of course this will only works if your server also accepts 'cors' requests.
Here is an example of how you could enable CORS in an Apache Server
SetEnvIfNoCase Access-Control-Request-Method "(GET|POST|PUT|DELETE|OPTIONS)" IsPreflight=1
SetEnvIfNoCase Origin ".*" AccessControlAllowOrigin=$0
SetEnvIfNoCase Origin "https://(url1.com|url2.com)$" AccessControlAllowOrigin=$0
Header always set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header always set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS" env=IsPreflight
Header always set Access-Control-Allow-Headers "Content-Type, Authorization, Accept, Accept-Language" env=IsPreflight
Header always set Access-Control-Max-Age "7200" env=IsPreflight
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteCond %{ENV:IsPreflight} 1
RewriteRule ^(.*)$ $1 [R=204,L]
The above code will inject the CORS headers in the response when its necessary.
With this code your server will allow CORS only from the the domains "url1.com" or "url2.com".
Here are some references
https://developer.mozilla.org/en-US/docs/Web/API/Request/mode
https://fetch.spec.whatwg.org/#simple-header

Thanks a lot! More than 6 hours to solve this.
In my nodejs server
npm install --save cors
at app.js I inserted the lines:
var cors = require('cors');
var app = express();
app.use(cors());
and in my react client:
var shape_for_db = JSON.stringify(layer.geometry);
const trechoRede = {
method: "POST",
mode: "cors",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: shape_for_db
};

The mode:"no-cors" options appears to be the issue. Remove that option and the Content-Type should be set to "application/json"

Related

Fetch API CORS error: Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight response

I'm trying to get data from an API of mine and I'm getting this error message in Chrome:
Access to fetch at 'https://myapi.amazonaws.com/accounts' from origin 'http://localhost:3000'
has been blocked by CORS policy: Request header field authorization is not allowed by
Access-Control-Allow-Headers in preflight response.
Since it's CORS, Chrome is doing a OPTIONS preflight request, which gets a 204 response with the following headers back:
access-control-allow-credentials: true
access-control-allow-origin: *
access-control-max-age: 3600
access-control-request-headers: *
access-control-request-method: GET, POST, PUT, PATCH, OPTIONS, DELETE
apigw-requestid: R64AgjukPHcEJWQ=
charset: utf-8
date: Tue, 10 May 2022 17:27:05 GMT
Then it makes the desired POST request with the following headers:
accept: application/json
authorization: Bearer some.very.long.string
Referer: http://localhost:3000/
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36
And finally, here is the base code for the request (JS Fetch API):
const result = await fetch(`${process.env.MY_API_URL}/accounts`, {
method: 'POST',
mode: 'cors',
headers: new Headers(
Accept: 'application/json',
'Accept-Encoding': 'gzip, deflate, br',
Connection: 'keep-alive',
Authorization: `Bearer ${accessToken}`,
),
body: JSON.stringify({
accountId,
name,
}),
})
if (!result.ok || result.status !== 200)
throw new Error("Couldn't get data")
const jsonResponse = await result.json()
return jsonResponse
Any thoughts on what might be going on?
You need to set access-control-allow-headers in the preflight response, e.g.:
access-control-allow-headers: *
You can read more about Access-Control-Request-Headers and Access-Control-Allow-Headers
The headers
access-control-request-headers: *
access-control-request-method: GET, POST, PUT, PATCH, OPTIONS, DELETE
belong into the request, not into the response. You probably also need to set access-control-allow-methods in the preflight response, e.g.:
access-control-allow-methods: GET, POST, PUT, PATCH, OPTIONS, DELETE

Setting http headers with angular

I'm tring to add a header called "access-token" to all my http request like this:
var app= angular.module("MainModule", ["ngRoute"]);
app.run(function($http){
$http.defaults.headers.common['access-token'] =ACCESSTOKEN;
})
and in my service:
service.get= function (x) {
console.log(ACCESSTOKEN)
return $http({
method: "GET",
headers: {
'Content-Type': 'application/json',
'access-token': ACCESSTOKEN
},
crossDomain: true,
url: GETSERVICE.replace("{id}", x),
dataType: 'json'
}).then(function (response) {
if (response.data) {
return response.data;
} else {
return $q.reject(response.data);
}
}, function (response) {
return $q.reject(response.data);
});
}
the problem is that i can't see the header in the network. There is only the OPTION request without my header.
my Back end cors configuration is like:
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, UPDATE, OPTIONS");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, access-token");
chain.doFilter(req, res);
Any ideas how to fix it?
TY
EDIT 1:
Here is the OPTION request without modifiy headers
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7
Access-Control-Request-Headers: access-token
Access-Control-Request-Method: GET
Cache-Control: no-cache
Connection: keep-alive
Host: localhost:8081
Origin: http://localhost:9080
Pragma: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
and whit modify headers (worked):
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7
Access-Control-Request-Headers: access-token
Access-Control-Request-Method: GET
access-token: 1520963789861
Cache-Control: no-cache
Connection: keep-alive
Host: localhost:8081
Origin: http://localhost:9080
Pragma: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36
whit modify headers I have the token in the request
CORS exists to secure APIs so that random clients do not make calls to them.
JavaScript has to take permissions to be able to make calls to those APIs. Browser is supposed to do all the heavy lifting related to CORS. But the only requirement is that the server should return the following HTTP headers for an OPTIONS request from a client:
Access-Control-Allow-Origin: <Origin fetched from the request>
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, DELETE
Access-Control-Allow-Headers: <ACCESS-CONTROL-REQUEST-HEADERS fetched from request>
If that is NOT an option, then on the client side, following code can be added to prevent all OPTIONS requests, which compromises security:
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
$httpProvider.defaults.headers.get = {};
}]);
See: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing
That OPTIONS request is called "preflight request". It only checks if your client has a right to send a request at all (when a server has a configured CORS). If server responds positively then your browser automatically send a full request with all you provided headers.
$httpProvider or $http module:
//with the provider, in the app.config():
$httpProvider.defaults.headers.post['Content-Type'] = 'application/json; charset=utf-8';
$http.defaults.headers.common['Content-Type'] = 'application/json; charset=utf-8';
Ok I will tell you what were the problem.
The genial man who write the rest api that I call in cross domain checked the value of the token also in the OPTION request going in null pointer.
Solved adding a filter for the option request.
TY for all

CORS cookie not set in any browser

Response has valid set-cookie header, shows up in response inspector and everything:
But it doesn't set it and therefore doesn't send it with next requests. window.document.cookie returns empty string. Setting path or expires doesn't help, neither does domain=localhost.com;.
Starting to lose my mind after 2 days, Im missing something or it's impossible? I've googled a lot.
Details:
No cookie, CORS related errors
API: https://abc123.api.api-domain.com/
App: http://www.localhost.com/ (set in hosts file, it's actually 127.0.0.1/localhost)
Response headers:
OPTIONS:
Access-Control-Max-Age: '600'
Access-Control-Allow-Headers: 'Content-Type, Cookie'
Access-Control-Allow-Origin: 'http://www.localhost.com'
Access-Control-Allow-Credentials: 'true'
Access-Control-Allow-Methods: 'OPTIONS, POST'
POST:
Access-Control-Allow-Origin: 'http://www.localhost.com'
Access-Control-Allow-Credentials: 'true'
Set-Cookie: 'customCookie=somehash; domain=.localhost.com;'
Fetch function:
return fetch('https://abc123.api.api-domain.com/', {
method: 'POST',
credentials: 'include', // to allow cookies
headers: {
'content-type': 'application/json'
},
body: JSON.stringify(someData),
}).then(res => {
return res.json();
});
Request headers:
Host: "abc123.api.api-domain.com"
Origin: "http://www.localhost.com"
Referer: "http://www.localhost.com/page"

Angular POST cross origin error while POSTMAN works

I try to POST from my angular login service:
$http.post('https://xyz/login',
{
headers: {
'Content-type': 'application/json',
'Accept': 'application/json',
'signature': 'asd'
}
And I get this error:
XMLHttpRequest cannot load https://xyz/login. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:1337' is therefore not allowed access.
I tried this headers:
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
And also these:
"Access-Control-Allow-Origin": "*";
"Access-Control-Allow-Headers": "X-Requested-With";
"Access-Control-Allow-Methods": "GET, POST", "PUT", "DELETE";
The interesting thing, is that the POSTMAN works.
What shoud I have to do?
Thanks.
Your request includes non-simple headers Content-type and signature which must be included in the response's Access-Control-Allow-Headers header.
(Content-type is sometimes a simple header, but only for particular values. application/json is not one of those values, and it causes Content-type to become non-simple.)
Add Content-type to Access-Control-Allow-Headers in your server's preflight response.
POSTMAN is not bound by the same-origin policy, so it does not require CORS support from the server.
Is your browser making an OPTIONS request before POSTing?
check the NET tab
I've had issues before where an OPTIONS request was being made by the browser or Angular (don't know which) and the server did not have ...
"Access-Control-Allow-Methods": "GET, POST", "PUT", "DELETE", "OPTIONS";
Not sure if you already have the information you need. But in my local web-server - when I make an http request using postman here is what it adds to the header:
headers:
{ host: 'localhost',
connection: 'keep-alive',
pragma: 'no-cache',
'cache-control': 'no-cache',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36',
accept: '/',
referer: 'http://localhost/',
'accept-encoding': 'gzip, deflate, sdch',
'accept-language': 'en-US,en;q=0.8' },
And here is what I see in the rawHeaders:
[ 'Host',
'localhost',
'Connection',
'keep-alive',
'Pragma',
'no-cache',
'Cache-Control',
'no-cache',
'User-Agent',
'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36',
'Accept',
'/',
'Referer',
'http://localhost/',
'Accept-Encoding',
'gzip, deflate, sdch',
'Accept-Language',
'en-US,en;q=0.8' ],
So perhaps you just need to fake your client to be a recognized browser client.

Angularjs set custom header parameters

In angularjs i must set a custom header for a POST
So i make:
var config = { 'Content-Type': 'application/x-www-form-urlencoded', 'TenantCode': 'MYTENANT', 'LoginType': 'PASSW' };
So i execute the post
$http.post(urlBase + '/Token', data, config)
Anyway when i inspect the request i have
OPTIONS /Token HTTP/1.1
Host: test.strokein.it
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://localhost:54599
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/46.0.2490.86 Safari/537.36
Access-Control-Request-Headers: accept, content-type
Accept: */*
Referer: http://localhost:54599/index.html
Accept-Encoding: gzip, deflate, sdch
Accept-Language: it-IT,it;q=0.8,en-US;q=0.6,en;q=0.4
and i don't see my header parameter
Why? What's the problem?
I think your config needs to look something like this:
var config = {
headers : {
'Content-Type': 'application/x-www-form-urlencoded',
'TenantCode': 'MYTENANT',
'LoginType': 'PASSW'
}
};
Looking at this specification of config.
That is your preflight request.
You have a CORS problem because you are testing from localhost to test.strokein.it
Easy fix would be you upload your test script to your server.
But in general, browser will send one more request after it gets an OK CORS response from your server i.e.
'Access-Control-Allow-Origin' : '*'
'Access-Control-Allow-Methods': 'GET, OPTIONS, PUT'
'Access-Control-Allow-Headers': 'Content-Type'
Then you should see your custom headers along with data on that POST request.
Read more here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

Categories

Resources