TurboGears / tg2

Python web framework with full-stack layer implemented on top of a microframework core with support for SQL DBMS, MongoDB and Pluggable Applications
http://www.turbogears.org/
Other
803 stars 77 forks source link

Where to add CORS headers #90

Closed GO3LIN closed 6 years ago

GO3LIN commented 7 years ago

I am developing a REST API using the awesome framework TG, but I'm getting the CORS error in my front-end: « Access-Control-Allow-Origin » header is missing.

I googled turbogears cors but didn't find anything about this subject. So where's the best place to put the CORS headers for all my routes (controllers actions).

Thanks in advance for your help.

amol- commented 7 years ago

_before method of the controller that exposes the API is usually a good place. See http://turbogears.readthedocs.io/en/latest/turbogears/objectdispatch.html#dispatching-entry-points

Just add a tg.response.headers.update({'Access-Control-Allow-Origin': '*'}) there and it should do the trick.

Note that you probably only want to allow your own domains, * is usually not what you want.

GO3LIN commented 7 years ago

Thanks for your answer, but actually, the problem seems to be a bit different, because when the browser sends the OPTIONS request (in preflight), the server responds with 404 Not found. Hence, the server didn't recognize the route with the OPTIONS method. I tried to define an option function in the controller but in vain. Maybe, this also needs to be handled in the _before hook ? Many thanks in advance

amol- commented 7 years ago

ah ok, if the issue is when the browser issues a preflight request then you might be facing some dispatch issues. Are you using a RestController or a plain TGController?

GO3LIN commented 7 years ago

I am using RestController.

Mero89 commented 7 years ago

i have the same issue

amol- commented 7 years ago

@GO3LIN in case of RestController you must name the method options:

class SomeRestController(RestController):
    @expose()
    def options(self, *args, **kwargs):
        return 'OK'

class RootController(BaseController):
    somerest = SomeRestController()

That will allow you to handle the preflight request for /somerest and subpaths. If you want to handle it for any path you probably want to use an application wrapper and catch the option method.

Mero89 commented 7 years ago

@amol- Thanks man, it works. @GO3LIN don't test it, it really works.

GO3LIN commented 7 years ago

Good job guys. This is working as charm, for anyone going through the same issue, for us the problem was that we forgot the @expose decorator wich is very important, because you need to make this route availble through the restcontroller.

@amol- I suggest opening a PR for exposing the options method by default in the restcontroller as it's the case for flask framework. I think that future people dont have to worry about the overhead of exposing the options method. Their first objective will have to define the CORS headers and respect its policy rather than having to handle 404 http not found responses.

Best.

lebouquetin commented 7 years ago

Hi all, I agree with @GO3LIN - as this is a common requirement when dealing with APIs. +1 for a PR exposing options() method by default

amol- commented 7 years ago

Uhm, I don't see how the default options implementation could provide a valid response for CORS. It can certainly provide the Access-Control-Allow-Methods by inspecting the implemented methods, but it would be impossible to fill the Access-Control-Allow-Origin header.

GO3LIN commented 7 years ago

@amol- The default options implementation should not add any header, it just prevents from dealing with 404 HTTP responses. I created a PR, can you review it ? Thanks

amol- commented 7 years ago

Thanks for your pull request, I have some family related business this week and I'm unable to access a PC for most of the day, so I'm sorry if my feedbacks are slow. I added a few comments to the pull request.

alexbodn commented 4 years ago

hello friends, how could i do the same with a tgcontroller?

GitHK commented 4 years ago

hello friends, how could i do the same with a tgcontroller?

The response was already given in this page: https://github.com/TurboGears/tg2/issues/90#issuecomment-318507877

Implement the _before method on your controller; should look a bit like this:

def _before(self, *args, **kw):
    tg.response.headers.update({'Access-Control-Allow-Origin': '*'})
lukakiro commented 3 years ago

Hi, I'm using the _before method of a RestController to add the necessary CORS headers, but this controller requires authentication and if the request is not authenticated, tg responds without calling that _before method.

So, I created an ApplicationWrapper that adds CORS headers, is this the right way?