Upload 4 files
Browse files- Dockerfile +24 -0
- README.md +19 -12
- app.py +80 -0
- requirements.txt +3 -0
Dockerfile
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Dockerfile
|
| 2 |
+
|
| 3 |
+
# 1. 使用一个轻量的 Python 基础镜像
|
| 4 |
+
FROM python:3.9-slim
|
| 5 |
+
|
| 6 |
+
# 2. 设置工作目录
|
| 7 |
+
WORKDIR /code
|
| 8 |
+
|
| 9 |
+
# 3. 复制依赖文件并安装
|
| 10 |
+
# 先复制 requirements.txt 可以利用 Docker 的层缓存机制
|
| 11 |
+
COPY requirements.txt .
|
| 12 |
+
RUN pip install --no-cache-dir --upgrade -r requirements.txt
|
| 13 |
+
|
| 14 |
+
# 4. 复制所有应用代码
|
| 15 |
+
COPY . .
|
| 16 |
+
|
| 17 |
+
# 5. 暴露端口。Hugging Face Spaces 默认使用 7860 端口
|
| 18 |
+
EXPOSE 7860
|
| 19 |
+
|
| 20 |
+
# 6. 运行应用的命令
|
| 21 |
+
# 使用 gunicorn 启动 Flask 应用
|
| 22 |
+
# app:app 的意思是:运行 app.py 文件中的 app 实例
|
| 23 |
+
# --bind 0.0.0.0:7860 使其可以被外部访问
|
| 24 |
+
CMD ["gunicorn", "--bind", "0.0.0.0:7860", "app:app"]
|
README.md
CHANGED
|
@@ -1,12 +1,19 @@
|
|
| 1 |
-
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
-
sdk: docker
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: My Flask Reverse Proxy
|
| 3 |
+
emoji: 🚀
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: green
|
| 6 |
+
sdk: docker
|
| 7 |
+
app_port: 7860
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
# Flask Reverse Proxy Server
|
| 11 |
+
|
| 12 |
+
This is a reverse proxy server built with Flask and deployed on Hugging Face Spaces.
|
| 13 |
+
|
| 14 |
+
## How to use
|
| 15 |
+
|
| 16 |
+
Send your requests to `https://<your-space-name>.hf.space/proxy/<target_path>`.
|
| 17 |
+
|
| 18 |
+
For example, to access `https://api.openai.com/v1/models`, you would make a request to:
|
| 19 |
+
`https://<your-space-name>.hf.space/proxy/v1/models`
|
app.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# app.py
|
| 2 |
+
import requests
|
| 3 |
+
from flask import Flask, request, Response
|
| 4 |
+
|
| 5 |
+
# --- 配置 ---
|
| 6 |
+
# 你想要代理的目标服务器地址
|
| 7 |
+
# 例如:'https://api.openai.com' 或 'https://google.com'
|
| 8 |
+
# 注意:结尾不要带斜杠 '/'
|
| 9 |
+
TARGET_URL = 'https://api.openai.com'
|
| 10 |
+
|
| 11 |
+
# --- Flask 应用 ---
|
| 12 |
+
app = Flask(__name__)
|
| 13 |
+
|
| 14 |
+
# 定义一个捕获所有路径的代理路由
|
| 15 |
+
# <path:path> 会捕获 /proxy/ 之后的所有子路径
|
| 16 |
+
@app.route('/proxy/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'])
|
| 17 |
+
def proxy(path):
|
| 18 |
+
"""
|
| 19 |
+
这是一个核心的代理函数。
|
| 20 |
+
它接收来自客户端的请求,并将其转发到 TARGET_URL。
|
| 21 |
+
"""
|
| 22 |
+
# 1. 构造目标 URL
|
| 23 |
+
target_url = f"{TARGET_URL}/{path}"
|
| 24 |
+
|
| 25 |
+
# 2. 获取客户端请求的参数 (查询字符串)
|
| 26 |
+
params = request.args
|
| 27 |
+
|
| 28 |
+
# 3. 获取客户端请求的头部,并进行一些处理
|
| 29 |
+
headers = {key: value for key, value in request.headers if key.lower() != 'host'}
|
| 30 |
+
# 替换 Host 头,使其看起来像是直接请求目标服务器
|
| 31 |
+
headers['Host'] = TARGET_URL.replace('https://', '').replace('http://', '')
|
| 32 |
+
|
| 33 |
+
# 如果你的目标API需要认证,可以在这里添加或修改headers
|
| 34 |
+
# 例如,从 Hugging Face Secrets 读取 API Key
|
| 35 |
+
# import os
|
| 36 |
+
# headers['Authorization'] = f"Bearer {os.environ.get('MY_API_KEY')}"
|
| 37 |
+
|
| 38 |
+
# 4. 获取客户端请求体
|
| 39 |
+
data = request.get_data()
|
| 40 |
+
|
| 41 |
+
print(f"[*] Forwarding request: {request.method} {target_url}")
|
| 42 |
+
|
| 43 |
+
try:
|
| 44 |
+
# 5. 使用 requests 库发送请求到目标服务器
|
| 45 |
+
# 使用 stream=True 来处理流式响应,例如大文件或 SSE (Server-Sent Events)
|
| 46 |
+
resp = requests.request(
|
| 47 |
+
method=request.method,
|
| 48 |
+
url=target_url,
|
| 49 |
+
headers=headers,
|
| 50 |
+
data=data,
|
| 51 |
+
params=params,
|
| 52 |
+
stream=True,
|
| 53 |
+
timeout=30 # 设置超时以避免请求挂起
|
| 54 |
+
)
|
| 55 |
+
|
| 56 |
+
# 6. 处理从目标服务器返回的响应
|
| 57 |
+
# 排除一些在代理中不应该传递的头部
|
| 58 |
+
excluded_headers = ['content-encoding', 'content-length', 'transfer-encoding', 'connection']
|
| 59 |
+
response_headers = {
|
| 60 |
+
key: value for key, value in resp.raw.headers.items()
|
| 61 |
+
if key.lower() not in excluded_headers
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
# 7. 创建一个新的 Flask Response 对象,将目标服务器的响应返回给客户端
|
| 65 |
+
# 使用 resp.iter_content 来流式传输响应内容,这对于大文件非常高效
|
| 66 |
+
return Response(resp.iter_content(chunk_size=1024), resp.status_code, response_headers)
|
| 67 |
+
|
| 68 |
+
except requests.exceptions.RequestException as e:
|
| 69 |
+
# 如果请求失败,返回一个错误信息
|
| 70 |
+
print(f"[!] Error forwarding request: {e}")
|
| 71 |
+
return Response(f"Proxying failed: {e}", status=502)
|
| 72 |
+
|
| 73 |
+
# 一个简单的健康检查端点
|
| 74 |
+
@app.route('/')
|
| 75 |
+
def index():
|
| 76 |
+
return "Flask Reverse Proxy is running!", 200
|
| 77 |
+
|
| 78 |
+
# 本地调试时使用
|
| 79 |
+
if __name__ == '__main__':
|
| 80 |
+
app.run(debug=True, port=5000)
|
requirements.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Flask
|
| 2 |
+
requests
|
| 3 |
+
gunicorn
|