I received the error message:
405 (Method Not Allowed)
when making an OPTIONS request. Backbone does this by default.
There seems to be lots of discussion about it in issue #284, but I didn't find a solution that worked with node-restify 2.8.2.
The code I am using is:
server.pre(restify.CORS());
server.use(restify.fullResponse());
What is the current recommended solution?
The problem seems to be that Backbone sends a couple extra headers that broke the CORs preflight.
I solved the problem by using:
restify.CORS.ALLOW_HEADERS.push('Accept-Encoding');
restify.CORS.ALLOW_HEADERS.push('Accept-Language');
server.use(restify.CORS())
Shame CORs is not more developer friendly. I had to fully understand CORs before I could solve it.
Express didn't have this problem. Perhaps they add more headers by default? Perhaps that is worth considering for other restify developers?
This is a pretty significant issue for the CORS middleware. I'd like to see this labeled as a bug instead of an improvement, since it prevents most usage of CORS.
A quick fix is to add a catch all for the options preflight request:
https://gist.github.com/nparsons08/baf1cd43bebd93dcf325
On Tue, Sep 9, 2014 at 10:10 AM, dark12222000 [email protected]
wrote:
This is a pretty significant issue for the CORS middleware. I'd like to
see this labeled as a bug instead of an improvement, since it prevents most
usage of CORS.—
Reply to this email directly or view it on GitHub
https://github.com/mcavage/node-restify/issues/664#issuecomment-54994019
.
I'm facing this problem with Angular's $http, and restify v2.8.4.
OPTIONS /auth HTTP/1.1
host: localhost:7777
connection: keep-alive
pragma: no-cache
cache-control: no-cache
access-control-request-method: POST
origin: http://localhost:9000
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
access-control-request-headers: accept, authorization, content-type
accept: */*
referer: http://localhost:9000/
accept-encoding: gzip, deflate, sdch
accept-language: en-US,en;q=0.8,en-GB;q=0.6
HTTP/1.1 405 Method Not Allowed
allow: POST
content-type: application/json
content-length: 67
I am also using:
server.use(restify.CORS());
server.use(restify.fullResponse());
and this solves the problem:
restify.CORS.ALLOW_HEADERS.push('authorization');
Is this the recommended solution? Is there a reason this isn't enabled by default?
Each client-side framework may need different headers to be allowed for CORs to work.
By default can we not just allow any headers to resolve this?
Thanks @amrav that fixed my problem!
@amrav - Thanks for the simple solution. Looks like we need to expose a better way of adding more ALLOW_HEADERS and EXPOSE_HEADERS in the CORS constructor.
How is this still not fixed? It should be marked as a bug, and a major one at that. When you enable CORS, I'd expect it to work like any other HTTP servers out there. I just want it to accept external request, that's all (no matter which headers are sent).
Even with the fix suggested above, I've removed all headers (used postman) and only had an OPTIONS request to the server and still had an "MethodNotAllowedError" while CORS and fullResponse enabled.
Michael, feel free to submit a PR Iinstead of raging about an open source
framework maintained by folks for free.
On Tuesday, October 6, 2015, Michel Boudreau [email protected]
wrote:
How is this still not fixed? It should be marked as a bug, and a major one
at that. When you enable CORS, I'd expect it to work like any other HTTP
servers out there. I just want it to accept external request, that's all
(no matter which headers are sent).Even with the fix suggested above, I've removed all headers (used postman)
and only had an OPTIONS request to the server and still had an
"MethodNotAllowedError" while CORS and fullResponse enabled.—
Reply to this email directly or view it on GitHub
https://github.com/restify/node-restify/issues/664#issuecomment-146064075
.
Via mobile
@yunong Yeah, looked through the code, can't say I liked what I saw. CORS only has 3 tests associated with it ('valid', 'invalid' and 'any origin') and I would have to add a plethora of tests to it. This is extremely concerning to me since this is suppose to be for a REST server and I'd imagine that CORS would be an extremely important red route for this.
Even still, while debugging, it doesn't even hit the CORS plugin at all, even with it in preflight. Seems to skip right over it. I think the optionsError function is suppose to be the one catching it, but it's weird that it needs to be there in the first place, and how it's currently looking for a 404 (mine's coming back as a 405) and that the URL needs to be '*' (I think it's suppose to be origin there...).
Looking through the code isn't inspiring a lot of confidence in using this library. If this isn't working, I can't fathom what else I'll discover if I use this server more.
Thanks for the feedback @mboudreau. We are working to improve the codebase as well as the processes around triaging issues and are always receptive to feedback about what areas need improvement. We appreciate you taking the time to provide us with your specific use case and trouble areas.
As always, we are more than happy to take PRs for code or documentation. That being said, there are only a handful of us who work on this, mostly in our spare time, and we try to address all issues as best we can.
:+1:
:+1:
:+1:
I had to add restify.CORS.ALLOW_HEADERS.push('authorization');, to get Authorization working with CORS, because the user agent adds Authorization to Access-Control-Request-Headers list when firing preflight with Authorization header. We are using OAuth2.
http://www.w3.org/TR/XMLHttpRequest/#the-setrequestheader%28%29-method
I'll add here the code I'm now adding to each of my API projects to get CORS to work. Feel free to use or abuse it at your leisure...
...
server.use( restify.CORS() );
...
// Lets try and fix CORS support
// By default the restify middleware doesn't do much unless you instruct
// it to allow the correct headers.
//
// See issues:
// https://github.com/mcavage/node-restify/issues/284 (closed)
// https://github.com/mcavage/node-restify/issues/664 (unresolved)
//
// What it boils down to is that each client framework uses different headers
// and you have to enable the ones by hand that you may need.
// The authorization one is key for our authentication strategy
//
restify.CORS.ALLOW_HEADERS.push( "authorization" );
restify.CORS.ALLOW_HEADERS.push( "withcredentials" );
restify.CORS.ALLOW_HEADERS.push( "x-requested-with" );
restify.CORS.ALLOW_HEADERS.push( "x-forwarded-for" );
restify.CORS.ALLOW_HEADERS.push( "x-real-ip" );
restify.CORS.ALLOW_HEADERS.push( "x-customheader" );
restify.CORS.ALLOW_HEADERS.push( "user-agent" );
restify.CORS.ALLOW_HEADERS.push( "keep-alive" );
restify.CORS.ALLOW_HEADERS.push( "host" );
restify.CORS.ALLOW_HEADERS.push( "accept" );
restify.CORS.ALLOW_HEADERS.push( "connection" );
restify.CORS.ALLOW_HEADERS.push( "upgrade" );
restify.CORS.ALLOW_HEADERS.push( "content-type" );
restify.CORS.ALLOW_HEADERS.push( "dnt" ); // Do not track
restify.CORS.ALLOW_HEADERS.push( "if-modified-since" );
restify.CORS.ALLOW_HEADERS.push( "cache-control" );
// Manually implement the method not allowed handler to fix failing preflights
//
server.on( "MethodNotAllowed", function( request, response )
{
if ( request.method.toUpperCase() === "OPTIONS" )
{
// Send the CORS headers
//
response.header( "Access-Control-Allow-Credentials", true );
response.header( "Access-Control-Allow-Headers", restify.CORS.ALLOW_HEADERS.join( ", " ) );
response.header( "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" );
response.header( "Access-Control-Allow-Origin", request.headers.origin );
response.header( "Access-Control-Max-Age", 0 );
response.header( "Content-type", "text/plain charset=UTF-8" );
response.header( "Content-length", 0 );
response.send( 204 );
}
else
{
response.send( new restify.MethodNotAllowedError() );
}
} );
@Qwerios I was looking at this issue while you were posting, and I finally made something close to what you did. And it works ! :+1:
Seems like you can publish it as a restify plugin on npm, while this issue can be resolved in restify itself.
Better solution than having an event on top of MethodNotAllowed (Just if you don't need to deploy any route on OPTIONS method).
app.use(
restify.CORS({
origins: [
'http://development.example.com',
'https://staging.example.com',
'https://www.example.com',
],
headers: [
"authorization",
"withcredentials",
"x-requested-with",
"x-forwarded-for",
"x-real-ip",
"x-customheader",
"user-agent",
"keep-alive",
"host",
"accept",
"connection",
"upgrade",
"content-type",
"dnt",
"if-modified-since",
"cache-control"
]
})
)
// Handle all OPTIONS requests to a deadend (Allows CORS to work them out)
app.opts( /.*/, ( req, res ) => res.send( 204 ) )
Thanks @Qwerios
This is my configuration in order to make angular-jwt work with restify.
app.pre(restify.CORS({
origins: ['http://localhost:3000'],
credentials: false,
headers: ['authorization']
}));
restify.CORS.ALLOW_HEADERS.push("authorization");
app.on( "MethodNotAllowed", function(req, res) {
if(req.method.toUpperCase() === "OPTIONS" ) {
// Send the CORS headers
res.header("Access-Control-Allow-Headers", restify.CORS.ALLOW_HEADERS.join( ", " ));
res.send(204);
}
else {
res.send(new restify.MethodNotAllowedError());
}
});
I hope it may be helpful for someone.
The CORS module has found a new home and has been updated to be both correct and stable :smile:
https://github.com/TabDigital/restify-cors-middleware/
I believe the recent changes address this issue, if I'm missing a nuance here please comment and I'd be happy to re-open this issue to discuss. We could also migrate this issue over to the new repo if needed :heart:
I'm facing this problem with Angular's $http, and restify v2.8.4.
OPTIONS /auth HTTP/1.1 host: localhost:7777 connection: keep-alive pragma: no-cache cache-control: no-cache access-control-request-method: POST origin: http://localhost:9000 user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 access-control-request-headers: accept, authorization, content-type accept: */* referer: http://localhost:9000/ accept-encoding: gzip, deflate, sdch accept-language: en-US,en;q=0.8,en-GB;q=0.6 HTTP/1.1 405 Method Not Allowed allow: POST content-type: application/json content-length: 67I am also using:
server.use(restify.CORS()); server.use(restify.fullResponse());and this solves the problem:
restify.CORS.ALLOW_HEADERS.push('authorization');Is this the recommended solution? Is there a reason this isn't enabled by default?
THIS IS THE BEST ANSWER FOR RESTIFY, I AM USING RESTIFY 4.2 AND IT SOLVE ALL MY PROBLEMS
Most helpful comment
Thanks @Qwerios
This is my configuration in order to make angular-jwt work with restify.
I hope it may be helpful for someone.