HTTP 405 error while trying to DELETE from web service - javascript

I have a simple Java web service that handles my SQL method with Jersey. The HTTP call is from an Angular project. GET and POST are working fine, but when I try a DELETE, I get an HTTP 405 error.
This is how I call the method in Angular:
deletaDados(id){
this.service.deleteData(id)
}
+
deleteData(id){
return this.http.delete(`${this.api}/${id}`).subscribe((res) => {
});;
}
And this is the DELETE Java method:
#DELETE
#Path("{id}/")
public Response delete(#PathParam("id") long id) throws SQLException, ClassNotFoundException{
ofertaDAO dao = new ofertaDAO();
dao.delete(id);
return Response
.status(200)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers", "origin, content-type, accept, authorization")
.header("Access-Control-Allow-Credentials", "true")
.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD")
.header("Access-Control-Max-Age", "1209600")
.entity(id)
.build();
}
Seem right... No idea why I'm getting the 405 error.

If the DELETE coming from your frontend JavaScript code is a cross-origin request, then your browser (automatically on its own) will send a CORS preflight OPTIONS request first.
So it seems like the 405 you’re seeing may be the response to that preflight OPTIONS request — and if so, then you’ll need to have an explicit OPTIONS handler in your server-side Java code.
That OPTIONS handler should just send back a response with a 200 status and the necessary CORS headers, with no response body; so, something like this:
#OPTIONS
public Response options(){
return Response
.status(200)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers", "origin, content-type, accept, authorization")
.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD")
.header("Access-Control-Max-Age", "1209600")
.build();
}
Incidentally, also note that for the Access-Control-Max-Age response header there’s probably not much point in setting a value that’s any greater than 600 (10 minutes) — because if you do set a value greater than that for it, Chrome will just clamp it to 600 anyway.
And as far as why you don’t also run into that 405 when you send a GET or POST from your frontend JavaScript code, the reason is that the GET and POST requests your code is sending don’t have characteristics (such as custom headers) that’ll trigger your browser to do a preflight. But cross-origin DELETE requests always trigger browsers to do a preflight.

Related

ERR_INVALID_HTTP_RESPONSE when sending request in chrome to python server

I have this server in python:
class MyServer(SimpleHTTPRequestHandler):
def do_POST(self):
...
some code here
...
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'POST')
self.send_header('Access-Control-Allow-Headers', 'Access-Control-Allow-Headers, Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers')
self.end_headers()
self.send_response(200)
if __name__ == "__main__":
webServer = HTTPServer((hostName, serverPort), MyServer)
print("Server started http://%s:%s" % (hostName, serverPort))
try:
webServer.serve_forever()
except KeyboardInterrupt:
pass
webServer.server_close()
print("Server stopped.")
But when I try to make a request in my js code in chrome, I get this error: POST http://localhost:8080/ net::ERR_INVALID_HTTP_RESPONSE
I have read that it is cors problem and I need to add the headers Access-Control-Allow-Origin, and I did and it didn't help.
Anyone has any idea how to fix it?
You need to call send_response first, then your custom send_header calls, then end_headers, then send whatever data you are sending. SimpleHTTPRequestHandler is extremely primitive, and expects you to understand the HTTP protocol.

Error HTTP GET object list

I get an error when I try to retrieve a list of objects from a link (php server).
Blocking of a multi-origin request (cross-origin request): the "same
source" policy does not allow access to the remote resource located at
http: //localhost/eReport/index.php. Reason:
"Access-control-authorization-origin" token missing in the CORS
"Access-Control-Allow-Headers" CORS header.
I added a header like this tuto that is recommended on this link but I still have this error.
Can you help me please ?
My Service page:
#Injectable()
export class ReportService{
private baseUrl: string = 'http://localhost/report/reports.php';
constructor(private http : Http){}
getAll(): Observable<Report[]>{
let report$ = this.http
.get(`${this.baseUrl}`, { headers: this.getHeaders()})
.map(mapReports);
return report$;
}
private getHeaders(){
// I included these headers because otherwise FireFox
// will request text/html
let headers = new Headers();
headers.append('Accept', 'application/json');
headers.append('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8');
return headers;
}
get(id: number): Observable<Report> {
let report$ = this.http
.get(`${this.baseUrl}/report/${id}`, {headers: this.getHeaders()})
.map(mapReport);
return report$;
}
My php page
header("Access-Control-Allow-Origin: *");
$tab = array(
array('id'=> '12', 'name'=> 'test','description' => '2018-04-01','url'=>'../../../assets/img/chat1.png' ),
array('id'=> '13', 'name'=> 'test','description' => '2018-04-01','url'=>'../../../assets/img/highcharts.png' )
);
echo json_encode($tab);
?>
Perhaps the quickest fix is to change your base url in the Angular app to /report/reports.php if the requests are going to the same server that served the app.
Your request is not working because when the client sends content of type application/json, the browser doesn't send the request right away. If you restart your browser then observe the network tab you will notice that instead of your GET, an OPTIONS request is first send, that includes headers similar to these:
Origin: yourserver
Access-Control-Request-Method: GET
Access-Control-Request-Headers: Content-Type, Accept
In this scenario, the browser expects the server to return not just the Access-Control-Allow-Origin header (which you're already doing), but all of these:
Access-Control-Allow-Origin: yourserver (or *)
Access-Control-Allow-Methods: GET (or a list eg: GET, POST, OPTIONS)
Access-Control-Allow-Headers: Content-Type, Accept (the same headers from above)
So you need to read the request headers from the previous block, and use their values when setting the response headers. If you have the apache_request_headers() method it's pretty easy. You can also get them from the $_SERVER superglobal.
// set required headers:
header("Access-Control-Allow-Origin: $_SERVER[HTTP_ORIGIN]");
header("Access-Control-Allow-Methods: $_SERVER[HTTP_ACCESS_CONTROL_REQUEST_METHOD]");
header("Access-Control-Allow-Headers: $_SERVER[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]");
See this helpful article

JxBrowser get post body in custom ProtocolHandler

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.

Cross-Origin Request Blocked Angular JS Put request

I'm developing a REST-ful application using Yii framework for the server side and Angular JS for the client side
I'm using the restfulyii extension to generate the api
:And I'm facing a problem when I'm sending a PUT request.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at ..... This can be fixed by moving the resource to the same domain or enabling CORS.
But it's working for post + get requests
I saw different solutions but none of them worked.
I tried to put those is server side
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
header("Access-Control-Allow-Headers: x-requested-with, Content-Type, origin, authorization, accept, client-security-token");
header("Access-Control-Max-Age: 1000");
and tried to put this code in the angular js module:
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
and also I tried to put
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
The request converted into OPTIONS request
and the response from the server became as following:
Access-Control-Allow-Headers:x-requested-with, Content-Type, origin, authorization, accept, client-security-token
Access-Control-Allow-Methods:GET, POST, PUT, DELETE, OPTIONS Access-Control-Allow-
Origin:http://localhost:8383
Access-Control-Max-Age:1000
Connection:close
Content-Type:text/html Date:Fri, 24 Oct 2014 06:49:32 GMT
Server:Apache/2.4.7 (Win32) OpenSSL/1.0.1e PHP/5.5.9 X-Powered-By:PHP/5.5.9
I have a base controller for all my rest controllers that use restangular which has the following events.
public function restEvents()
{
$this->onRest('req.cors.access.control.allow.origin', function() {
return ['*']; //List of sites allowed to make CORS requests
});
$this->onRest('req.cors.access.control.allow.methods', function() {
return ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']; //List of allowed http methods (verbs)
});
$this->onRest('req.auth.cors', function ($allowed_origins) {
if (in_array('*', $allowed_origins)) {
return true;
}
if((isset($_SERVER['HTTP_ORIGIN'])) && (( array_search($_SERVER['HTTP_ORIGIN'], $allowed_origins)) !== false )) {
return true;
}
return false;
});
$this->onRest('req.cors.access.control.allow.headers', function($application_id) {
return ["X_{$application_id}_CORS", "Content-Type", "Authorization", "X_REST_REQUEST"];
});
}
Client side I am using restangular with the following options:
RestangularProvider.setDefaultHttpFields({withCredentials: true});
RestangularProvider.setDefaultHeaders({X_REST_CORS: 'Yes'});
RestangularProvider.setDefaultHttpFields({cache: false});
I hope this helps....

AngularJS: POST Data to External REST API

I have a basic AngularJS service setup like so:
app.factory('User', function($resource) {
return $resource('http://api.mysite.com/user/:action:id/:attr', {}, {
history: {
method: 'GET',
params: {
attr: 'history'
}
},
update: {
method: 'POST',
params: {
name: 'test'
}
}
});
});
and I use it like this:
User.history({id: 'testID'}, function(data) {
console.log('got history');
console.log(data);
});
User.update({id: 'me'}, function(data) {
console.log('updated');
console.log(data);
});
Problem one: User.update(), despite having the method set to POST, keeps sending OPTIONS as the request method.
Though Chrome Dev tools reports the request header Access-Control-Request-Method:POST is sent as well (Not sure if that means anything).
Problem two: I keep getting an error with CORS, despite having these headers set in the API code:
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS");
This problem only shows up though if making a non-GET request.
What's the proper way to be handling this? I've also looked into JSONP, but with this being a RESTful api, I'm not sure how to get around the problems with only GET support.
Your two problems are actually one problem. The OPTIONS request is part of the CORS process. For POST requests, the browser first sends an OPTIONS call, and the server responds if it is okay to execute it.
If the OPTIONS request fails, Angular / Chrome shows you the reason in the console. For example:
OPTIONS https://*** Request header field Content-Type is not allowed by Access-Control-Allow-Headers. angular.min.js:106
XMLHttpRequest cannot load https://***. Request header field Content-Type is not allowed by Access-Control-Allow-Headers.
You probably have to set Access-Control-Allow Headers on the server, too:
header('Access-Control-Allow-Headers: Content-Type, x-xsrf-token')
x-xrsf-token is for angular' to prevent CSRF. You may have to add more headers, depending on what you send from the client.
Here is a very good guide on CORS: https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
In AngularJS to make CORS working you also have to overwrite default settings of the angular httpProvider:
var myApp = angular.module('myApp', [
'myAppApiService']);
myApp.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}
]);
Just setting useXDomain to true is not enough. AJAX request are also
send with the X-Requested-With header, which indicate them as being
AJAX. Removing the header is necessary, so the server is not rejecting
the incoming request.
Note: Answer only works for older AngularJS version previous to 1.2. With 1.2 and above you don't have to do do anything to enable CORS.
Better to solve this problem at the server. On apache you can solve it like this in a .htaccess file. This is a source of pain for angular development and can be solved in angular as well but its probably not the best way to do it.
Header set Access-Control-Allow-Origin "*"
Header add Access-Control-Allow-Headers "origin, x-requested-with, content-type"
Header add Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS"

Categories