I'm using axios in my application, but I'm having a hard time setting the content of the request.
There's currently a call to a URL using $.ajax like this:
$.ajax({
method: 'POST',
data: { 'accountId': accountId },
url: serverUrl,
/* success: ... */
});
And when I look at this request in Chrome dev tools, at the end I see something like this:
Now, I'm trying to do the same thing with axios:
axios.post(serverUrl, { accountId: accountId })
.then(/* ... */);
But, when I look at the request in Chrome dev tools, I have this:
How can I get axios to do the same formatting as jQuery? And maybe the question is that: are they different or it's just the representation?
Also, I noticed that the jQuery call is somehow adding this header: x-requested-with: XMLHttpRequest, but to have the same header in axios, I have to set it manually. Is it normal? Am I missing an axios configuration to add this header?
Thank you
Some frameworks use this header to detect XHR requests, for example. Grails Spring uses this header to identify the query XHR and gives the JSON response or the HTML response as a response.
Most Ajax libraries (Prototype, JQuery and Dojo from version 2.1) include the X-Requested-With header, which indicates that the query was made using XMLHttpRequest instead of running by clicking a regular hyperlink or submitting a form button.
A good reason for security is that it can prevent CSRF attacks, because this header can not be added to the cross domain of the AJAX request without the server's consent through CORS.
Only the following headers are allowed:
To accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type
any others call the "before flight" request in the browsers supported by CORS.
Without CORS, X-Requested-With can not be added to an XHR request with a cross domain.
If the server checks the presence of this header, it knows that the request did not initiate an attempt to make a request on behalf of the user from the attacker's domain using JavaScript.
It also checks that the request was not sent from the usual HTML form, from which it is more difficult to verify that it is not a cross domain without the use of tokens. (However, checking the Origin header can be an option in supported browsers although you leave old browsers vulnerable.)
See also: https://markitzeroday.com/x-requested-with/cors/2017/06/29/csrf-mitigation-for-ajax-requests.html
So also read for greater understanding:
FormData()
https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects
https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData
Request Payload
What's the difference between "Request Payload" vs "Form Data" as seen in Chrome dev tools Network tab
As documented here, You can use the URLSearchParams API to send data in the application/x-www-form-urlencoded format using axios.
Example from offical docs:
var params = new URLSearchParams();
params.append('param1', 'value1');
params.append('param2', 'value2');
axios.post('/foo', params);
Related
On a Network tab (Chrome browser) we can see a Headers tab.
Further if we have a request list we see General, Response Headers and Request Headers lists.
For example:
General:
Request URL: wss://some.url.com/websocket
Request Method: GET
Status Code: ...
Response Headers:
OWN-KEY-FROM-SERVER: true
etc...
If that was a XMLHttpRequest, we can use getAllResponseHeaders method of xhr, but WebSocket doesn't have something like this according to the WebSocket API.
I need to get from server some trigger and he is inside Responses Headers list.
Maybe somebody know a decision with that.
If using chrome is not the only option for you, then:
I used wireshark to manitor my websocket traffic. It included all the headers and bodies and works perfectly. Just set filter for tcp.port==YOUR_PORT || (websocket) and start manitoring.
The CORS specification states that if a HTTP request is considered 'simple', no CORS and/or preflight is needed.
I'm trying to do a HTTP request that appears to have these conditions:
I'm not setting custom HTTP headers.
I'm using a POST method.
I'm using application/x-www-form-urlencoded.
Code sample:
$.ajax({
type: 'POST',
url: 'http://example.org/',
data: {foo: 'bar'}
});
However, when running this, the request is still preflighted with OPTIONS (which fails). Is there something obvious I'm missing?
A few references to simple requests:
https://w3c.github.io/webappsec-cors-for-developers/#cross-origin-send-permissions-simple-safelisted-request
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Simple_requests
CORS restrictions affect all requests going from one domain to another. example: localhost -> example.com. I end up just going to my example.com server-side code and make sure I enable requests from myotherexample.com where I am making calls from. Do this using the CORS header while developing locally
Access-Control-Allow-Origin: *
Another example when you are ready for production
Access-Control-Allow-Origin: https://myotherexample.com
I realized my mistake when re-reading the documentation.
What I am doing is indeed a simple request.
The request was actually being sent to the server without an OPTIONS request and succeeded!
However, I was not allowed to read the response when it came back. So the true difference between simple and non-simple CORS requests is:
For simple requests a preflight is not needed, but the server still needs to respond with CORS headers.
So my options are as follows:
I ignore the error. The request succeeded after all, I just can't read the response.
I implement CORS server-side anyway. In my case I can't, because I don't control the target server.
I use a html form to submit the data, call .submit() on it and target a hidden iFrame.
I proxy the request through a server that I do control.
Future:
I think, but I'm not sure, that the new Fetch API also allows a mode where you can make HTTP requests cross-domain, opt-out of CORS and simply be denied access to the HTTP response. If this is correct, then this would be the ideal way to do this (to me). But I don't know 100% certain if this is indeed how this works.
I`m trying to fetch results from remote server (inaturalist.org) using angularjs $http. The server use headers to specify Paging information (total entries, page, etc).
My problem is when using IE (Edge, IE11 tested) I cant see all the headers.
$http({
method : 'GET',
url : 'https://www.inaturalist.org/observations.json?page=1&per_page=30'})
.success(function (data, status, headers) {
scope.headers = headers();
});
});
See https://jsbin.com/rohoda/edit?js,output
Any idea whats wrong ?
This is a bug in Internet Explorer's implementation of the XMLHttpRequest object. Since you are making a cross domain request CORS rules apply. It is a GET request so it is not necessary to make a pre-flight OPTIONS request. The server correctly returns the following response header:
Access-Control-Expose-Headers: X-Per-Page, X-Total-Entries
and yet you cannot access the X-Total-Entries response header using the getResponseHeader() method (which is what this header variable represents in the success callback).
The only browser that fully and correctly implements this Access-Control-Expose-Headers CORS header is Google Chrome.
You may find the following article useful and especially the Access-Control-Expose-Headers problem section right at the bottom:
All browsers (except Google Chrome) have buggy getRequestHeader()
implementations, so the headers may not be accessible to clients even
after you set the Access-Control-Expose-Headers header. In my example,
ETag header accessible only in Google Chrome browser. Safari return
only simple response headers, while Firefox doesn't return ANY
response headers.
I am afraid that the only workaround here is to setup a proxy script on your domain that will act as a bridge between your domain and the remote domain. Then make the AJAX request to your own domain to avoid the need of using CORS.
I am attempting to retrieve a class (with GET) from Parse using a client key. I was able to send a successful request using Advanced Rest Client for Google Chrome; I used X-Parse-Application-Id and X-Parse-Client-Key headers.
[edit] [edit2]
Response headers (obtained from Chrome Developer Tools OPTIONS):
HTTP/1.1 200 OK
Access-Control-Allow-Headers: X-Parse-REST-API-Key, X-Parse-Javascript-Key, X-Parse-Application-Id, X-Parse-Client-Version, X-Parse-Session-Token, X-Requested-With, X-Parse-Revocable-Session, Content-Type
Access-Control-Allow-Methods: OPTIONS, POST, GET, PUT, DELETE
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 86400
Content-Type: application/json; charset=utf-8
Date: Sun, 29 Nov 2015 04:23:08 GMT
Server: nginx/1.6.0
X-Parse-Platform: G1
X-Runtime: 0.000118
Content-Length: 0
Connection: keep-alive
However, attempting to do the same in an Angular app gives me the following error:
XMLHttpRequest cannot load https://api.parse.com/1/classes/GenResources. Request header field X-Parse-Client-Key is not allowed by Access-Control-Allow-Headers in preflight response.
Parse says it supports using cross-origin resource sharing, and I was able to make the request earlier using a different client so I'm pretty sure the server isn't the issue. I wouldn't be able to modify what the response header is anyways.
Here's the code I used to form the GET request.
var ng_portal = angular.module("ngPortal", []);
ng_portal.controller("GenResourcesCtrl", ["$http", function($http) {
$http({
method: "GET",
url: PARSE_URL + "/1/classes/GenResources",
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": PARSE_APP_ID,
"X-Parse-Client-Key": PARSE_CLIENT_KEY
}
}).then(
function success(res) {
console.log(res);
},
function error(res) {
console.log(res);
}
);
}]);
You are setting custom headers in the request, which will trigger a pre-flight (OPTIONS) request. The response from that request must include a header called "access-control-allow-headers" with the value being a list of the headers you are trying to set.
See https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
specifically the section on pre-flight requests.
I suggest using the browser developer tools to look at the headers of the requests and responses to see if they conform to the CORS spec. From the error message you provided, it looks like the server hosting the cross domain call you are making, does not support custom headers. If you see otherwise, please update your question with the headers and I can provide more help.
This seems to be an issue with Parse.com actually. After exactly one frustrated hour, I came across this Google Groups post
Relevant quote
From my testing, this never ( client or javascript key) worked via javascript rest interactions through the browser.
I actually created a Parse Bug on this:
https://developers.facebook.com/bugs/488204124680438
Because I thought both of those keys should work through the browser ( WITHOUT NEEDING TO USE A SDK ).
I’d suggest reading reading my bug. I still think the the correct implementation is to enable these keys to work properly with browser requests because it works if you do it outside the browser.
But alas, they don’t seem to get the issue, or don’t understand why disabling it only in the browser doesn’t make sense since you can use it on any other platform without issues. Just… Doesn’t… Make… Sense.
I instead used my JavaScript Key X-Parse-Javascript-Key (which, according to the docs as of today, only works with their JavaScript SDK) and it works fine as a drop-in replacement for X-Parse-Client-Key
Trying to get the Request headers from the XHR object, but with no luck, is there a hidden method or property of that object that will expose the headers sent by the browser?
I already know how to set custom request headers and view the response headers, I'm looking to get a list of all REQUEST headers sent, ones created by the browser and my custom ones.
I'm using webkit/chrome, don't care about other browsers.
EDIT: I'm not looking to monitor the request, I'm building a web app and I need to list those headers and display them within the app, please don't tell me about fiddler, firebug and chrome tools, that's not what I'm looking for.
There is no method in the XMLHttpRequest API to get the sent request headers. There are methods to get the response headers only, and set request headers.
You'll have to either have the server echo the headers, or use a packet sniffer like Wireshark.
Try using Fiddler Web Debugger.
http://www.fiddler2.com/fiddler2/
You can capture the request that was sent in any browser as well as inspect the request headers, response headers, and even copy a capture sent request and send it out as your own.
Assuming you are using jQuery, and you're looking for anything attached, but maybe not ALL headers sent, this could help. Not sure if it meets your exact needs, (since the browser tends to add its own things), but if you need to grab your own headers first, this works:
$.ajaxSetup({
beforeSend: function (jqXHR, settings) {
if(!(settings.headers && settings.headers.token)) {
//no token header was set, so set the request header
jqXHR.setRequestHeader('token', newtoken);
}
}
})
As the name suggests, sent headers were SENT, (duh)! And the XMLHttpRequest class doesn't store sent headers in RAM or put sent headers in an instance of XMLHttpRequest... which is good for performance.
If you want to get the headers that have been sent, all you need to do is to create a log mechanism.
And since custom request header are created through XMLHttpRequest.prototype.setRequestHeader(), You need to intercept XMLHttpRequest.prototype.setRequestHeader();
var sentHeaders = {}
var originalXMLHttpRequest_setRequestHeader = XMLHttpRequest.prototype.setRequestHeader;
XMLHttpRequest.prototype.setRequestHeader = function(header, value) {
sentHeaders[header] = value;
originalXMLHttpRequest_setRequestHeader.call(this, header, value);
}
That's all. No need for external library nor Wireshark. All done within Javascript;
Just make sure the intercept code above executed before any XMLHttpRequest initialization.
Ps. this code will obviously only intercept the custom header created through setRequestHeader(). The XMLHttpRequest itself will set some default headers which can't be accessed through this method.