Search code examples
corsgoogle-cloud-runquartflask-cors

Is Cloud Run removing the CORS headers from my backend?


I have developed a simple backend in Python, using Quart, Quart-CORS and SQLAlchemy. When I try the different endpoints on localhost with Postman, the CORS headers are correctly returned. As soon as I deploy it on Google Cloud Run, it seems like Google removes all the CORS headers on every response that the backend returns, so my frontend rejects the responses.

Has anyone come across this issue before? Any ideas on how to fix it? Please let me know if any additional information from my side is needed.

Thank you,


Solution

  • I kept working on it and it seems to be working so far. The following code combines two different solutions:

    • Adding the CORS headers manually to the make_response method provided by Quart.
    • Using methods from the add-on library Quart-CORS.

    It would probably be enough with any of these solutions by itself, but somehow it's only with both that I managed to fix the issue.

    Python code:

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    """
    Script used to launch the API.
    """
    
    from __future__ import print_function
    from quart import Quart, Blueprint, request, make_response, jsonify
    from quart_cors import cors, route_cors
    from http import HTTPStatus
    import secrets
    
    blueprint_v0_login_options = Blueprint('v0_login_options', __name__)
    blueprint_v0_login_post = Blueprint('v0_login_post', __name__)
    
    
    CORS_SETTINGS = {'allow_origin': '*'}
    
    
    @blueprint_v0_login_options.route('/v0/login', methods=['OPTIONS'], provide_automatic_options=False)
    @route_cors(**CORS_SETTINGS, provide_automatic_options=False)
    async def v0_login_options():
        return await make_response(
            jsonify(None),
            HTTPStatus.ACCEPTED,
            {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept',
                'Access-Control-Allow-Methods': 'OPTIONS, POST'
            }
        )
    
    
    @blueprint_v0_login_post.route('/v0/login', methods=['POST'], provide_automatic_options=False)
    @route_cors(**CORS_SETTINGS, provide_automatic_options=False)
    async def v0_login_post():
    
        json = await request.get_json()
    
        return await make_response(
            jsonify(json),
            HTTPStatus.ACCEPTED,
            {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept'
            }
        )
    
    
    def main():
    
        # Start API server.
        quart_app = Quart(__name__)
        quart_app = cors(quart_app, **CORS_SETTINGS)
        quart_app.secret_key = secrets.token_urlsafe(16)
    
        # Register blueprints.
        quart_app.register_blueprint(blueprint_v0_login_options)
        quart_app.register_blueprint(blueprint_v0_login_post)
    
        quart_app.run(host='0.0.0.0', port=8081)
    
    
    if __name__ == "__main__":
        main()
    

    Dockerfile:

    FROM python:3.8
    
    COPY . /api
    WORKDIR /api
    
    # Prepare Python.
    RUN apt-get update
    RUN pip install --upgrade pip
    ENV PYTHONUNBUFFERED=1
    
    # Install module.
    RUN python setup.py install
    
    # Run.
    CMD PYTHONPATH=. api
    

    Thank you!!