Mutating request.base_url in Flask

2019-04-25 05:15发布

I have a Flask application behind a Load balance that terminates SSL. I have code that "detects" when SSL is being used and mutates the request object:

@app.before_request
def before_request():
    x_forwarded_proto = request.headers.get('X-Forwarded-Proto')
    if  x_forwarded_proto == 'https':
        request.url = request.url.replace('http://', 'https://')
        request.url_root = request.url_root.replace('http://', 'https://')
        request.host_url = request.host_url.replace('http://', 'https://')

I then have a blueprint view function:

admin = Blueprint('admin', __name__, url_prefix='/admin')
@admin.route('/login')
def login():
    print request.url

The output of this function is (when I go to /admin/login) is always http:// instead of https:// (even though it should have been mutated in the before_request function.

Any ideas on how I can fix this?

1条回答
小情绪 Triste *
2楼-- · 2019-04-25 06:01

Turns out request is a proxied object. I'm not sure of the internals but it's "reset" on each import. I solved the issue by subclassing Request

class ProxiedRequest(Request):
    def __init__(self, environ, populate_request=True, shallow=False):
        super(Request, self).__init__(environ, populate_request, shallow)
        # Support SSL termination. Mutate the host_url within Flask to use https://
        # if the SSL was terminated.
        x_forwarded_proto = self.headers.get('X-Forwarded-Proto')
        if  x_forwarded_proto == 'https':
            self.url = self.url.replace('http://', 'https://')
            self.host_url = self.host_url.replace('http://', 'https://')
            self.base_url = self.base_url.replace('http://', 'https://')
            self.url_root = self.url_root.replace('http://', 'https://')

app = Flask(__name__);
app.request_class = ProxiedRequest
查看更多
登录 后发表回答