如何在Flask中携带请求数据重定向至外部URL
解决Flask重定向无法传递请求数据的问题
你现在的问题核心是重定向是客户端行为:当你返回301时,浏览器会重新发起一个新请求到目标URL,但原始请求的POST数据、部分头信息会丢失(HTTP规范里3xx重定向对POST会转成GET,除非用307/308,但依赖客户端和后端配合)。要完整传递请求数据,应该让Flask作为中间层,直接把原始请求转发到可用后端,再将后端的响应返回给客户端——也就是做反向代理。
下面是修改后的代码,实现完整的请求转发:
from flask import Flask, request, make_response import requests import json app = Flask(__name__) HEADERS = {"your-custom-headers": "value"} # 保留你原有的自定义头 @app.route('/<path:text>', methods=['GET', 'POST', 'PUT', 'DELETE']) def main(text): backend_ping_urls = ['https://<PLACE-1>/api/ping', 'https://<PLACE-2>/api/ping'] target_backend_base = None # 检测可用后端 for ping_url in backend_ping_urls: print(f'Testing url: {ping_url}') try: resp = requests.get(ping_url, headers=HEADERS, timeout=5) if resp.status_code == 200: data = resp.json() if data == 'pong': target_backend_base = ping_url.replace('/api/ping', '') break else: print(f'Response from {ping_url} was: {data}') else: print(f'Status code of {ping_url} was {resp.status_code}') except requests.exceptions.RequestException as e: print(f'Error connecting to {ping_url}: {str(e)}') continue if not target_backend_base: return 'Backends are not available :(' # 构造目标URL target_url = f'{target_backend_base}/{text}' print(f'Forwarding request to: {target_url}') # 复制原始请求头,调整Host为目标后端域名 forward_headers = dict(request.headers) forward_headers['Host'] = target_backend_base.split('://')[1] # 合并自定义头(如果需要覆盖原始头) forward_headers.update(HEADERS) # 根据请求方法转发对应数据 try: if request.method == 'GET': forward_resp = requests.get( target_url, headers=forward_headers, params=request.args, timeout=10 ) elif request.method == 'POST': if request.is_json: forward_resp = requests.post( target_url, headers=forward_headers, json=request.get_json(), timeout=10 ) else: # 支持表单数据和文件上传 forward_resp = requests.post( target_url, headers=forward_headers, data=request.form, files=request.files, timeout=10 ) else: # 兼容PUT、DELETE等其他请求方法 forward_resp = requests.request( method=request.method, url=target_url, headers=forward_headers, data=request.get_data(), params=request.args, timeout=10 ) # 构造响应返回给客户端 response = make_response(forward_resp.content, forward_resp.status_code) # 复制后端响应头(排除部分不需要的系统头) for key, value in forward_resp.headers.items(): if key.lower() not in ['content-encoding', 'transfer-encoding', 'connection']: response.headers[key] = value return response except requests.exceptions.RequestException as e: print(f'Error forwarding request to {target_url}: {str(e)}') return 'Failed to forward request to backend', 500 if __name__ == '__main__': app.run(debug=True)
关键说明
- 反向代理逻辑:Flask直接作为中间层转发请求,客户端完全感知不到后端的存在,所有请求数据(包括POST表单、JSON、文件)都会完整传递
- 请求信息完整复制:涵盖请求方法、查询参数、请求头、请求体,确保后端收到的请求和客户端直接访问时一致
- 响应透传:把后端的状态码、响应头、响应内容原封不动返回给客户端,保证客户端体验和直接访问后端一致
- 异常处理:增加了超时、连接异常的捕获,避免Flask服务因后端故障崩溃
内容的提问来源于stack exchange,提问作者Alberto Carmona
相关产品推荐
相关产品推荐

