405 Method Not Allowed when using headers in the fetch api - javascript

I am trying to Make an ajax request using fetch, and when I do, I get a 405 (Method Not Allowed) error.
I am executing it like this:
fetch(url, {
method: 'get',
headers: {
'Game-Token': '123'
}
});
And that is giving me an error. If I remove the headers, the request goes through. However, I need that header for validation on the server.
fetch(url, { method: 'get' });
I have the following setup in my .htaccess file:
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS, FETCH"
Header set Access-Control-Allow-Credentials "true"
Header set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization, X-CSRF-TOKEN, Game-Token, developerKey"
Header set X-Frame-Options "SAMEORIGIN"
Header set Access-Control-Expose-Headers "Game-Token"
I am not sure what is causing this to not go through.

So, this had nothing to do with JavaScript or the .htaccess. Instead it has to do with Lumen. We need to catch the OPTIONS request and reply back. What we did was create a middleware file that checked for the OPTIONS method and responds with a 200.
use Closure;
class CorsMiddleware
{
public function handle($request, Closure $next)
{
if ($request->isMethod('OPTIONS'))
{
return response('',200);
}
return $next($request);
}
}

Related

Fetch PATCH request not allowed (CORS)

So I've been using fetch for quite a while without any issues. I've created plenty of APIs and had to implement CORS in multiple APIs.
However, today I can't seem to get CORS to work for a single patch request. It works for get/post/delete without issues, but patch isn't working.
I have read fetch patch request is not allowed, and sadly I already wrote patch fully capitalized, so this isn't a solution for me.
My request:
{
method: 'PATCH', //using POST here makes everything work fine.
json: true,
headers: defaultHeaders,
body: JSON.stringify({
type: 'analytics_analyzers',
attributes: {
status: active ? 1 : 2,
ssid: getState().config.ssid
}
})
}
And the server's .htaccess file:
SetEnvIf Origin "http(s)?://(www\.)? (whitelistUrl1|whitelistUrl2|whitelistUrl3)$" AccessControlAllowOrigin=$0
Header always set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
Header always set Access-Control-Allow-Credentials true
SetEnvIf Access-Control-Request-Headers ".*" AccessControlHeaders=$0
Header always set Access-Control-Allow-Headers: %{AccessControlHeaders}e env=AccessControlHeaders
SetEnvIf Access-Control-Request-Method ".*" AccessControlMethod=$0
Header always set Access-Control-Allow-Methods: %{AccessControlMethod}e env=AccessControlMethod
Options request
Error message
Anyone has any ideas to what I'm doing wrong here?
In fact, when we send a not simple cors request to server side, like DELETE/ PUT / PATCH, but not include POST/GET/HEAD,the browser will send a OPTIONS request (preflight) to server side then ask if it is support the METHOD/ORIGIN/HEADERS, so if you just specified the PATCH request allowed method is not enough.
It's my example codes, just for this question, may be not so graceļ¼Œhope u never mind ...
app.patch('/cors', (req, res) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length,Server,Date,access-control-allow-methods,access-control-allow-origin");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS,PATCH");
res.send('ok')
})
app.options('/*', (req, res) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length,Server,Date,access-control-allow-methods,access-control-allow-origin");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS,PATCH");
res.send('send some thing whatever')
})

CORS Post Request Fails

I built an API with the SLIM Micro-Framework. I setup some middleware that adds the CORS headers using the following code.
class Cors{
public function __invoke(Request $request, Response $response, $next){
$response = $next($request, $response);
return $response
->withHeader('Access-Control-Allow-Origin', 'http://mysite')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
}
}
For my front-end, I used VueJS. I setup VueResource and created a function with the following code.
register (context, email, password) {
Vue.http({
url: 'api/auth/register',
method: 'POST',
data: {
email: email,
password: password
}
}).then(response => {
context.success = true
}, response => {
context.response = response.data
context.error = true
})
}
In chrome, the following error is logged to the console.
XMLHttpRequest cannot load http://mysite:9800/api/auth/register. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://mysite' is therefore not allowed access.
Oddly enough, GET requests work perfectly.
You half 1/2 the solution here.
What you are missing is an OPTIONS route where these headers need to be added as well.
$app->options('/{routes:.+}', function ($request, $response, $args) {
return $response
->withHeader('Access-Control-Allow-Origin', 'http://mysite')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
});
This happens because preflight request is of OPTIONS type. You need to make an event listener on your request, which checks the type and sends a response with needed headers.
Unfortunately i don't know Slim framework, but here's the working example in Symfony.
First the headers example to be returned:
// Headers allowed to be returned.
const ALLOWED_HEADERS = ['Authorization', 'Origin', 'Content-Type', 'Content-Length', 'Accept'];
And in the request listener, there's a onKernelRequest method that watches all requests that are coming in:
/**
* #param GetResponseEvent $event
*/
public function onKernelRequest(GetResponseEvent $event)
{
// Don't do anything if it's not the master request
if (!$event->isMasterRequest()) {
return;
}
// Catch all pre-request events
if ($event->getRequest()->isMethod('OPTIONS')) {
$router = $this->container->get('router');
$pathInfo = $event->getRequest()->getPathInfo();
$response = new Response();
$response->headers->set('Access-Control-Allow-Origin', $event->getRequest()->headers->get('Origin'));
$response->headers->set('Access-Control-Allow-Methods', $this->getAllowedMethods($router, $pathInfo));
$response->headers->set('Access-Control-Allow-Headers', implode(', ', self::ALLOWED_HEADERS));
$response->headers->set('Access-Control-Expose-Headers', implode(', ', self::ALLOWED_HEADERS));
$response->headers->set('Access-Control-Allow-Credentials', 'true');
$response->headers->set('Access-Control-Max-Age', 60 * 60 * 24);
$response->send();
}
}
Here i just reproduce the Origin (all domains are allowed to request the resource, you should probably change it to your domain).
Hope it will give some glues.
Actually CORS is implemented at browser level. and Even with
return $response
->withHeader('Access-Control-Allow-Origin', 'http://mysite')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
chrome and Mozilla will not set headers to allow cross origin. So, you need forcefully disable that..
Read more about disabling CORS
Disable same origin policy in Chrome
CORS can be hard to config. The key is that you need to set the special headers in your server and your client, and I don't see any Vue headers set, besides as far as I know http is not a function. However here is some setup for a post request.
const data = {
email: email,
password: password
}
const options = {
headers: {
'Access-Control-Expose-Headers': // all of your headers,
'Access-Control-Allow-Origin': '*'
}
}
Vue.http.post('api/auth/register', JSON.stringify(data), options).then(response => {
// success
}, response => {
// error
})
Notice that you need to stringify your data and you need to expose your headers, usually including the Access-Control-Allow-Origin header.
What I did in one of my own apps was to define interceptors so I don't worry to set headers for every request.
Vue.http.headers.common['Access-Control-Expose-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, x-session-token, timeout, Content-Length, location, *'
Vue.http.headers.common['Access-Control-Allow-Origin'] = '*'

Microsoft Cognitive Services JavaScript Request 'Access-Control-Allow-Origin'

Hy, when I try to access the Microsoft Cognitive Services API via JavaScript from my server/local machine I get the following error.
XMLHttpRequest cannot load http://api.projectoxford.ai/vision/v1.0/analyze?visualFeatures=Categories. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://myUrl.com' is therefore not allowed access. The response had HTTP status code 401.
This is my request code:
function requestAPI(){
var params = {
// Request parameters
"visualFeatures": "Categories"
};
$.ajax({
url: "http://api.projectoxford.ai/vision/v1.0/analyze?" + $.param(params),
beforeSend: function(xhrObj){
// Request headers
xhrObj.setRequestHeader("Content-Type","application/json");
xhrObj.setRequestHeader("Ocp-Apim-Subscription-Key","{myKey}");
},
type: "POST",
// Request body
data: "{'url':'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg'}",
})
.done(function(data) {
alert("success");
})
.fail(function() {
alert("error");
});
}
In my .htaccess I already added:
Header add 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"
When I test the request with hurl.it it works. Just from my server it doesn't.
Looks like you are setting CORS headers for your server which means someone can make cross-domain request to your server.
Microsoft Cognitive Services have to add these headers on their server so that you can make cross-domain request to them or you have to use JSONP.

Having trouble with cross domain CORS request

I am using PHP for server-side and Backbone.js on front end. I can do GET and POST requests, but can't seem to get a PUT or DELETE to work.
I am not 100% sure where the best place to put headers are. I have them in two places. One in the .htaccess file as follows.
#Header always set Access-Control-Allow-Origin "http://www.fitnesstimer.dev"
#Header always set Access-Control-Allow-Methods "POST, GET, PUT, DELETE, OPTIONS"
#Header always set Access-Control-Allow-Headers "origin, x-requested-with, Content-Type,X-Custom-Header"
#header always set Access-Control-Allow-Credentials "true"
Then in the header of my Controller I have this.
header('Access-Control-Allow-Origin: http://www.fitnesstimer.dev');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Origin, Content-Type, Accept, Authorization, X-Request-With, X-Custom-Header');
header('Access-Control-Allow-Credentials: true');
My AJAX call looks like this.
$.ajax({
type: 'PUT',
url: 'http://www.fitnesstimerapi.dev/user/deleteuser/' + userId,
contentType: "application/json",
xhrFields: {withCredentials: true },
dataType: "text",
success: function() {
alert( 'User removed!' );
},
error: function( err ) {
console.log( "ERROR: ", err );
}
});
I have tried both PUT and DELETE as the type and neither works. I get the following error.
XMLHttpRequest cannot load http://www.fitnesstimerapi.dev/user/deleteuser/11. Response for preflight has invalid HTTP status code 404
Thanks to the comment by jfriend00:
The mention of "preflight" in the error means that the browser is sending the "OPTIONS" command and not getting the answer it expects from your server. Does your PHP properly implement the "OPTIONS" request as part of your CORS support
I found the answer.
I added this to my index.php file.
// respond to preflights
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
// return only the headers and not the content
// only allow CORS if we're doing a GET - i.e. no saving for now.
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']) &&
$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'] == 'GET' &&
isset($_SERVER['HTTP_ORIGIN']) &&
is_approved($_SERVER['HTTP_ORIGIN'])) {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: X-Requested-With');
}
exit;
}

Angular http post request - No 'Access-Control-Allow-Origin' header is present on the requested resource

I am trying to send data to servlet using angular http post,
var httpPostData = function (postparameters,postData){
var headers = {
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods' : 'POST, GET, OPTIONS',
'Accept': 'application/json'
};
return $http ({
method : 'POST',
url : 'http://localhost:8080/json/jasoncontroller',
params : postparameters,
headers: headers,
data : postData
}).success (function (responseData){
return responseData.data;
})
}
But i am keep on getting error that No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
I did have set following headers on my servlet
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
response.addHeader("Access-Control-Max-Age", "3600");
response.addHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
if i remove data from http post it works fine, but no luck with data.
Actually what happens is in some frameworks two calls are made,
OPTIONS which checks what methods are available,
And then there is the actual call.
OPTIONS require just empty answer 200 OK
if(request.methord == 'OPTIONS'){
res.send(200);
} else {
next();
}
You can also install this chrome extension to enable cors, that is the easy way out !

Categories

Resources