Fetch Request Not Working - javascript

I am trying to add a custom header, X-Query-Key, to a HTTP request using Fetch API or request but when I add this to the header of the request it appears to fail at setting the headers and the Request Method is set to OPTIONS for some reason.
When I remove the header it goes back to being GET as it should do.
Sample code looks like below:
const options = {
url: url,
headers: {
'Accept': 'application/json',
'X-Query-Key': '123456' //Adding this breaks the request
}
};
return request(options, (err, res, body) => {
console.log(body);
});

Try this:
const headers = new Headers({
"Accept": "application/json",
"X-Query-Key": "123456",
});
const options = {
url: url,
headers: headers
};
return request(options, (err, res, body) => {
console.log(body);
});
If that does not solve the issue, it may be related to CORS.

Custom headers on cross-origin requests must be supported by the
server from which the resource is requested. The server in this
example would need to be configured to accept the X-Custom-Header
header in order for the fetch to succeed. When a custom header is set,
the browser performs a preflight check. This means that the browser
first sends an OPTIONS request to the server to determine what HTTP
methods and headers are allowed by the server. If the server is
configured to accept the method and headers of the original request,
then it is sent. Otherwise, an error is thrown.
So you will have 2 requests if use custom headers, first one with method OPTIONS to check if server allows custom headers and after that if the server response is 200 OK and allows your originary request the second one will be send
Working with the Fetch API

Related

Make a correct POST request and get response data

I have an application hosted on pythonanywhere.com. It throws a 400 error if sended data does not contain data property, otherwise it returns a response data. This is Flask code of the server:
#app.route('/api', methods=['POST'])
def get_post():
if not request.json or not 'data' in request.json:
abort(400)
data = request.json['data']
# do something with the data...
return jsonify({'response': str(data)}), 200
And my front-end part of application should send a POST request with a data and get a response. I am trying to use fetch but it gets a 400 error though I send a JSON object with a data object:
function sendData(value) {
data = { 'data': value };
fetch('http://' + appUrl, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
mode: 'no-cors',
body: JSON.stringify(data),
})
.then(data => { return data.json() })
}
Also I tried to use XMLHttpRequest:
var xhr = new XMLHttpRequest();
xhr.open("POST", 'http://' + appUrl, true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(data);
But I can't find out how to disable CORS and get a response data.
if you are having CORS issue, always check if the server accept your origin of request (other than pythonanywhere.com) if not, you should allow it from your server.
you mentioned that you are using Flask as your backend, you might want to check out this library:
https://flask-cors.readthedocs.io/en/latest/
if you follow the docs from the link, you can allow, accept http request depends on the parameter you provided.
Happy Coding

Why is the response body empty (0 bytes on network tab) for this request? Is it to do with this being an extension?

When I use the fetch API (Or xmlhttprequest) I get a 0 byte response. Here is a sample of my code:
fetch("https://myurl", {
method: "POST",
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({content: content})
}).then(function(res){ return res.text()}).then(function(res){ return cb(res);});
In the network tab, and in the console.log(res) in the callback, the response is empty. I should note that the response is including a CORS response specifying my chrome extension (which is making the request)
Access-Control-Allow-Origin: chrome-extension://asdjkljuewyrjkhighqwend
When I use the requests library (python) and make the same request (copying and pasting the body of the request) I get a valid json response.
resp = requests.post("https://myurl", json=data)
resp.json() ->> {content}
Additionally, when I inspect the server after the Fetch requests, I can see that it happily responded with the json to the request, but something on the browser seems to be blocking it from getting through.
You need to move all XHR requests to the background part of your extension.
Chrome no longer accepts content scripts requests.
You can use runtime.sendMessage to send messages to a background process.
chrome.runtime.sendMessage(myMessageObject, async response => {
// Here is the response returned by the background process
});
And here is how to receive messages from the background perspective.
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
return true
})
I believe you're indeed looking at a CORS issue. Try including the following headers in the response from your server:
Access-Control-Allow-Origin: * // you already hve this one
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, PUT, POST, OPTIONS

POST Request Using fetch() Returns 204 No Content

I'm making a POST request to a node.js server and I'm having trouble getting it to work. Here's my request:
const headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'this-can-be-anything',
};
export const postVote = (id, vote) =>
fetch(`${uri}/posts/${id}`, {
method: 'POST',
headers,
body: JSON.stringify({options: vote}),
}).then(response => response.json())
.then(data => data)
.catch(err => console.log(err));
The function accepts an 'id' and a 'vote', both strings. The id is being used as part of the URI in the request, and the vote is being supplied as options so the API knows what to do with it. Both of the arguments are being passed correctly:
id = '8xf0y6ziyjabvozdd253nd'
vote = 'upVote'
Here's a link to the GitHub repository for the server/API:
Udacity Readable API
and a screenshot of the network when firing the request:
UPDATE: Added the second screenshot which shows status 200. Though it shows this and appears to have been successful, it still doesn't post to the server and the information stays the same.
What you are looking at is the OPTIONS request in the network tab. For cross origin requests, every request if preceeded by an OPTIONS request which tells the calling client (browser, for example) if those HTTP methods are supported by the remote server for use in crosss origin context.
Check the other requests out. If the OPTIONS request was responded to correctly by the server, the browser must automatically follow up with your POST request
EDIT:
Also, the docs specify the param name to be option whereas in your screenshot it is coming up as options.
Further reading: CORS
Try declaring the headers as such:
var headers = new Headers({
'Content-Type': 'application/json',
'Authorization': 'this-can-be-anything',
})

Angular 2 Http with custom headers getting 405

I've run into this issue with custom headers when trying to perform and Http GET request from angular 2. Preforming the same request from Postman works fine, however I get a following 405 error in Angular2:
OPTIONS http://[somehost.com]/api/v1/admin/account/singin 405 (Method Not Allowed)
The API has a GET operation where you pass a username and password in the header and it returns a 200 with a token in it's header. Here is an example of the code block I am using:
constructor (private http: Http) {
}
login (userName: string, password: string): Observable<any> {
const endPointUrl = this.baseUrl + '/admin/account/singin';
const headers = new Headers({
'Accept': 'application/json',
'X-Rem-Username': userName,
'X-Rem-Password': password
});
const options = new RequestOptions({headers: headers});
return this.http.get(endPointUrl, options)
.map((response: Response) => {
console.log(response);
return response;
});
}
As I mentioned, performing this request in Postman and in he WebStorm REST client with these headers works fine. If I remove these 'X-Rem' headers I get a 401, which is expected. Any help would be appreciated, thanks.
Try this
const headers = new Headers({
'Accept': 'application/json',
'X-Rem-Username': userName,
'X-Rem-Password': password
});
this.http.get('url', {headers: headers})
This is not problem with angular app. Your app and rest api server are different server/domain. You should configure cross domain allow in server. Whenever you request any api on server by web browser, it first check cross domain allow options by request a OPTION method. In postman api directly send, there is no cross domain.
I am not sure but you can try add this header:
"Access-Control-Expose-Headers" : "Authorization"
I found it in this discussion

Angular $http options instead post

I make $http POST request to a server api but request method changes to OPTIONS.
I do it all with localhost. So I did the same request through the Postman and everything works
Service:
function httpReg(userData) {
console.log(userData)
return $http({
method: 'POST',
url: CONFIG.APIHost + '/auth/signup',
data: {
"username": userData.username,
"email":userData.email,
"password": userData.password
},
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
});
}
Screenshot:
(source: joxi.net)
Actually your preflight request is bounced back.
If the browser doesn't trusts the data source you are hitting the browser first sends a preflight request to that server and if that returns 200OK, then browser will send your original request.
The applies only to browsers, and other tools such as postman dosen't send and preflight requests, so your code might work their.
How to solve the problem.
Add headers for accepted options GET, POST, OPTIONS, PUT to the requested resource.
Yes it looks like cors problem.
Try one of the following:
Try to set the referrer in your header
Try this:
app.config(['$httpProvider', function ($httpProvider) {
//Reset headers to avoid OPTIONS request (aka preflight)
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
}]);
Remove the x-auth* settings from _app.js file of your yeoman/gulp settings.
Reference: AngularJS performs an OPTIONS HTTP request for a cross-origin resource

Categories

Resources