You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 20:05:23