Bottle Py: Enabling CORS for jQuery AJAX requests

前端 未结 4 1919
鱼传尺愫
鱼传尺愫 2020-11-28 08:40

I\'m working on a RESTful API of a web service on the Bottle Web Framework and want to access the resources with jQuery AJAX calls.

Using a REST client, the resource

相关标签:
4条回答
  • 2020-11-28 09:20

    Install a handler instead of a hook.

    There are two complementary ways I've done this in the past: decorator, or Bottle plugin. I'll show you both and you can decide whether one (or both) of them suit your needs. In both cases, the general idea is: a handler intercepts the response before it's sent back to the client, inserts the CORS headers, and then proceeds to return the response.

    Method 1: Install Per-route (Decorator)

    This method is preferable when you only want to run the handler on some of your routes. Just decorate each route that you want it to execute on. Here's an example:

    import bottle
    from bottle import response
    
    # the decorator
    def enable_cors(fn):
        def _enable_cors(*args, **kwargs):
            # set CORS headers
            response.headers['Access-Control-Allow-Origin'] = '*'
            response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, OPTIONS'
            response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'
    
            if bottle.request.method != 'OPTIONS':
                # actual request; reply with the actual response
                return fn(*args, **kwargs)
    
        return _enable_cors
    
    
    app = bottle.app()
    
    @app.route('/cors', method=['OPTIONS', 'GET'])
    @enable_cors
    def lvambience():
        response.headers['Content-type'] = 'application/json'
        return '[1]'
    
    app.run(port=8001)
    

    Method 2: Install Globally (Bottle Plugin)

    This method is preferable if you want the handler to execute on all or most of your routes. You'll just define a Bottle plugin once, and Bottle will automatically call it for you on every route; no need to specify a decorator on each one. (Note that you can use a route's skip parameter to avoid this handler on a per-route basis.) Here's an example that corresponds to the one above:

    import bottle
    from bottle import response
    
    class EnableCors(object):
        name = 'enable_cors'
        api = 2
    
        def apply(self, fn, context):
            def _enable_cors(*args, **kwargs):
                # set CORS headers
                response.headers['Access-Control-Allow-Origin'] = '*'
                response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, OPTIONS'
                response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'
    
                if bottle.request.method != 'OPTIONS':
                    # actual request; reply with the actual response
                    return fn(*args, **kwargs)
    
            return _enable_cors
    
    
    app = bottle.app()
    
    @app.route('/cors', method=['OPTIONS', 'GET'])
    def lvambience():
        response.headers['Content-type'] = 'application/json'
        return '[1]'
    
    app.install(EnableCors())
    
    app.run(port=8001)
    
    0 讨论(0)
  • 2020-11-28 09:27

    Also shouldn't you actually be using this?

    response.set_header('Access-Control-Allow-Origin', '*')
    response.add_header('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS')
    
    0 讨论(0)
  • 2020-11-28 09:27

    Consider letting your webserver, not Bottle, set the headers.

    Not sure whether this applies in your situation, but I've solved the problem in past projects by setting CORS headers for my Bottle application in Apache. It's easy to configure, keeps my Python code nice and clean, and is efficient.

    Information is available from many sources, but if you're using Apache, here's what my config looks like (more or less):

    <Location "/cors">
        Header set Access-Control-Allow-Headers "Origin, Content-Type"
        Header set Access-Control-Allow-Methods "POST, GET, OPTIONS"
        Header set Access-Control-Allow-Origin "*"
        Header set Access-Control-Request-Headers "Origin, Content-Type"
    </Location>
    
    0 讨论(0)
  • 2020-11-28 09:29

    Here's a minor improvement on @ron.rothman's method #2 for installing the CORS handler globally. His method requires you to specify that the OPTIONS method is accepted on every route you declare. This solution installs a global handler for all OPTIONS requests.

    @bottle.route('/<:re:.*>', method='OPTIONS')
    def enable_cors_generic_route():
        """
        This route takes priority over all others. So any request with an OPTIONS
        method will be handled by this function.
    
        See: https://github.com/bottlepy/bottle/issues/402
    
        NOTE: This means we won't 404 any invalid path that is an OPTIONS request.
        """
        add_cors_headers()
    
    @bottle.hook('after_request')
    def enable_cors_after_request_hook():
        """
        This executes after every route. We use it to attach CORS headers when
        applicable.
        """
        add_cors_headers()
    
    def add_cors_headers():
        if SOME_CONDITION:  # You don't have to gate this
            bottle.response.headers['Access-Control-Allow-Origin'] = '*'
            bottle.response.headers['Access-Control-Allow-Methods'] = \
                'GET, POST, PUT, OPTIONS'
            bottle.response.headers['Access-Control-Allow-Headers'] = \
                'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'
    

    ```

    0 讨论(0)
提交回复
热议问题