In one of my projects I use the JxBrowser in a Netbeans application where my ReactApp is running.
I want to send a post request from the ReactApp and intercept it in my custom Protocol Handler in the JxBrowser.
The request is done via 'superagent':
request
.post('http://my-url')
.send({test: 'it'})
.set('Accept', 'application/json')
.set('Content-Type', 'application/json')
.end(callback)
I receive the request in my ProtocolHandler but I do not know how to get the post body out of the request.
urlRequest.getUploadData() //<-- returns null
What is the correct way to get the posts body here?
You're making a cross-origin request. A preflight "OPTIONS" request is sent in this case and you need to handle it properly in your ProtocolHandler. In this particular case you should set the certain headers telling the browser that the requested features are allowed:
if (request.getMethod().equals("OPTIONS")) {
URLResponse urlResponse = new URLResponse();
String origin = request.getRequestHeaders().getHeader("Origin");
HttpHeadersEx headers = urlResponse.getHeaders();
headers.setHeader("Access-Control-Allow-Methods", "POST");
headers.setHeader("Access-Control-Allow-Headers", "Content-Type");
headers.setHeader("Access-Control-Allow-Origin", origin);
urlResponse.setStatus(HttpStatus.OK);
return urlResponse;
}
Also, in order to allow JxBrowser to detect the POST data type properly, you should set the "Content-Type" request header with the corresponding value. In this case it should be the "application/x-www-form-urlencoded".
request
.post('http://my-url')
.send({test: 'it'})
.set('Accept', 'application/json')
.set('Content-Type', 'application/x-www-form-urlencoded')
.end(callback)
Then you'll receive a POST request with your data. I recommend that you take a look at the following article that contains the details related to CORS: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
If you're making a request to the same origin, you can avoid handling cross-origin requests just by setting the proper "Content-Type" header.
Related
Using angular v1.3.1 i got a singular the following problem trying to implement a facade for making http request to a REST + JSON interface in the backend of the web app.
I got something like this in the code:
findSomething(value: number): ng.IPromise<api.DrugIndication[]> {
const getParams = { 'param' : 'value' };
const config:ng.IRequestShortcutConfig = {
headers: {
"Content-Type" : "application/json"
},
data: getParams
}
return this.$http.get(url,config);
}
And when the times comes to invoke it, i got an 400 Bad Request (btw: Great name for a band!) because the backend (made with Play for Scala) rejects the request inmediately. So making an inspection in the request i see that no data is being send in the body of the request/message.
So how i can send some data in the body of and HTTP Get request using angular "$http.get"?
Additional info: This doesn't happen if i the make request using the curl command from an ubuntu shell. So probably is an problem between Chrome and angular.js
If you inspect the network tab in chrome development tools you will see that this is a pre-flight OPTIONS request (Cross-Origin Resource Sharing (CORS)).
You have two ways to solve this.
Client side (this requires that your server does not require the application/json value)
GET, POST, HEAD methods only
Only browser set headers plus these
Content-Type only with:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Server side
Set something like this as a middleware on your server framework:
if r.Method == "OPTIONS" {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type,Authorization")
w.Header().Set("Access-Control-Max-Age", "86400") // firefox: max 24h, chrome 10min
return
}
For your specific framework this should work
Using config.data will send the data in the request body, use
config.params = getParams
This is from the documentation :
params – {Object.} – Map of strings or objects which will be serialized with the paramSerializer and appended as GET parameters
I am trying to access the header 'error-detail' as you can see in the browser network inspector (link above), the header gets returned. Server-wise I have also added the custom header to the 'Access-Control-Expose-Headers' to allow cross-domain requests as this was suggested to be the fix on other questions.
Below is the request to the server along with the success/error callbacks.
this.signon = function (request, onComplete, onError) {
console.log("Calling server with 'login' request...");
return $http.post("http://localhost:8080/markit-war/services/rest/UserService/login/", request)
.then(onComplete, onError);
};
var onLookupComplete = function(response) {
if (response.data.username)
{
//If user is returned, redirect to the dashboard.
$location.path('/dashboard');
}
$scope.username = response.data.username;
};
var onError = function(response) {
$scope.error = "Ooops, something went wrong..";
console.log('error-detail: ' + response.headers('error-detail'));
};
When I try access the response header as seen below:
console.log(response.headers());
console.log('error-detail: ' + response.headers('error-detail'));
This only outputs:
content-type: "application/json"
error-detail: null
Is there a reason why the error-detail header is not being mapped over to the response object?
I think you are on the right track. To have access to custom headers, your server needs to set this special Access-Control-Expose-Headers header, otherwise your browser will only allow access to 6 predefined header values as listed in the Mozilla docs.
In your screenshot such a header is not present in the response. You should have a look at the backend for this cors header to also be present in the response.
This is a CORS Issue. Because this is a cross-origin request, the browser is hiding most ot the headers. The server needs to include a Access-Control-Expose-Headers header in its response.
The Access-Control-Expose-Headers1 response header indicates which headers can be exposed as part of the response by listing their names.
By default, only the 6 simple response headers are exposed:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
If you want clients to be able to access other headers, you have to list them using the Access-Control-Expose-Headers header.
For more information, see MDN HTTP Header -- Access-Control-Expose-Headers
I am trying to make a POST request to the server (Which is a REST service)via javascript,and in my request i want to send a cookie.My below code is not working ,as I am not able to receive cookie at the server side.Below are my client side and server side code.
Client side :
var client = new XMLHttpRequest();
var request_data=JSON.stringify(data);
var endPoint="http://localhost:8080/pcap";
var cookie="session=abc";
client.open("POST", endPoint, false);//This Post will become put
client.setRequestHeader("Accept", "application/json");
client.setRequestHeader("Content-Type","application/json");
client.setRequestHeader("Set-Cookie","session=abc");
client.setRequestHeader("Cookie",cookie);
client.send(request_data);
Server Side:
public #ResponseBody ResponseEntity getPcap(HttpServletRequest request,#RequestBody PcapParameters pcap_params ){
Cookie cookies[]=request.getCookies();//Its coming as NULL
String cook=request.getHeader("Cookie");//Its coming as NULL
}
See the documentation:
Terminate these steps if header is a case-insensitive match for one of the following headers … Cookie
You cannot explicitly set a Cookie header using XHR.
It looks like you are making a cross origin request (you are using an absolute URI).
You can set withCredentials to include cookies.
True when user credentials are to be included in a cross-origin request. False when they are to be excluded in a cross-origin request and when cookies are to be ignored in its response. Initially false.
Such:
client.withCredentials = true;
This will only work if http://localhost:8080 has set a cookie using one of the supported methods (such as in an HTTP Set-Cookie response header).
Failing that, you will have to encode the data you wanted to put in the cookie somewhere else.
This can also be done with the more modern fetch
fetch(url, {
method: 'POST',
credentials: 'include'
//other options
}).then(response => console.log("Response status: ", response.status));
I'm trying to do an AJAX request to https://developers.zomato.com/api/v2.1/search referring to Zomato API
The server has headers:
"access-control-allow-methods": "GET, POST, DELETE, PUT, PATCH, OPTIONS",
"access-control-allow-origin": "*"
The problem is that the API requires additional headers set for user-key. But whenever I set custom headers then chrome would do a pre-flight request by sending an OPTIONS request to the above URL which is failing, and thus the AJAX request is failing as well.
If I don't set the headers, then I don't get a CORS error, but rather a forbidden error from server since I'm not setting user-key header.
Any way to go about this catch-22 situation?
Both Jquery and JavaScript way are failing:
$(document).ready(function () {
$.ajax({
url: 'https://developers.zomato.com/api/v2.1/search',
headers: {
'Accept': 'application/json',
'user_key': 'XXXXX'
},
success: function (data) {
console.log(data);
}
});
});
var xhr = new XMLHttpRequest();
var url = 'https://developers.zomato.com/api/v2.1/search';
xhr.open('GET', url, false);
xhr.setRequestHeader('Accept', 'application/json');
xhr.setRequestHeader('user_key', 'XXXXXX');
xhr.send(null);
if (xhr.status == 200) {
console.log(xhr.responseText);
}
Error I'm getting:
OPTIONS https://developers.zomato.com/api/v2.1/search
XMLHttpRequest cannot load https://developers.zomato.com/api/v2.1/search. 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:8000' is therefore not allowed access. The response had HTTP status code 501.
If somebody wants to reproduce you can get a free user-key here:
https://developers.zomato.com/api
There does not appear to be a work-around for this issue from a browser. The CORS specification requires a browser to preflight the request with the OPTIONS request if any custom headers are required. And, when it does the OPTIONS preflight, it does not include your custom headers because part of what the OPTIONS request is for is to find out what custom headers are allowed to be sent on the request. So, the server is not supposed to require custom headers on the OPTIONS request if it wants this to work from a browser.
So, if the server is requiring the custom headers to be on the OPTIONS request, then the server is just expecting something that will not happen from a browser.
See related answers that describe more about this here:
jQuery CORS Content-type OPTIONS
Cross Domain AJAX preflighting failing Origin check
How do you send a custom header in a cross-domain (CORS) XMLHttpRequest?
Using CORS for Cross-Domain Ajax Requests
And, another user with the same issue here:
Zomato api with angular
It appears the Zomato is not browser friendly, but requires access from a server where you don't have CORS restrictions.
FYI, the error coming back from Zomato is 501 which means NOT IMPLEMENTED for the OPTIONS command. So, it looks like it's not only that the key is not being sent with the OPTIONS command, but that Zomato does not support the OPTIONS command, but that is required for the use of custom headers on a cross-origin request from a browser.
You can't bypass Access-Control-Allow-Headers in preflight response.
However as mentioned by #Jaromanda X in comments, Zomato sends:
Access-Control-Allow-Headers:X-Zomato-API-Key
...meaning you can only send this non-standard header from browser. Also don't go too low-level in request definition when jQuery has pretty and prepared shorthands ...
TL;DR Working example:
$.ajax({
type: "GET", //it's a GET request API
headers: {
'X-Zomato-API-Key': 'YOUR_API_KEY' //only allowed non-standard header
},
url: 'https://developers.zomato.com/api/v2.1/dailymenu', //what do you want
dataType: 'json', //wanted response data type - let jQuery handle the rest...
data: {
//could be directly in URL, but this is more pretty, clear and easier to edit
res_id: 'YOUR_RESTAURANT_OR_PLACE_ID',
},
processData: true, //data is an object => tells jQuery to construct URL params from it
success: function(data) {
console.log(data); //what to do with response data on success
}
});
I am trying to make request with XMLHttpRequest from file://example.html to http://localhost/index.php. I read a lot about CORS(in this case origin is null, this is OK.) and i have no idea what i am doing wrong.
My request finishes well but the $_POST is empty! Except if i set "Content-type: application/x-www-form-urlencoded". But "text/plain" or "application/json" gives no result in $_POST... Why?
xhr.open("POST", "http://localhost/index.php", true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = handler;
xhr.send({'a':'12'});
You are probably doing one of these two things wrong:
If the content-type is not application/x-www-form-urlencoded, CORS must send a preflight request. That means that the browser will send before doing the POST request an OPTIONS request, which is used to determine if the POST request is allowed. Take a look here how this works.
Secondly, if you use xhr.setRequestHeader("Content-Type", "application/json"), the $_POST parameters will not be filled with parameters, this is only the case for application/x-www-form-urlencoded. To get the JSON you send, you will have to do:
<?php
$input = json_decode(file_get_contents("php://input"), true);
echo $input['a']; //echoes: 12
For more info, see this question.
Furthermore, if you go into the debugging facilities of any decent browser, it will create an error message if the CORS request is not allowed, please be sure to check if the CORS request was actually made by the browser.
I hope this helps you.
complementing #user23127 response
server side should have something like this to respond to the OPTIONS preflight request:
if (request.method === 'OPTIONS') {
htmlRes = HttpResponse()
htmlRes['Access-Control-Allow-Origin']='*' // or your not origin domain
htmlRes['Access-Control-Allow-Methods']='*' // or POST, GET, PUT, DELETE
htmlRes['Access-Control-Allow-Headers']='*' // Content-Type, X-REQUEST
}
// the rest of the code as if it was not a CORS request