This commit is contained in:
zhangquan 2026-03-31 09:40:10 +08:00
parent b08f29e8bf
commit 5faf98c651
2 changed files with 131 additions and 0 deletions

View File

@ -824,6 +824,8 @@ mark_x = answer_bbox[2] + 10 # 紧贴答案框
- ✅ 添加 URL 可访问性验证和 HTTP Headers 支持
- ✅ 实现超时保护机制单任务120秒总任务按图片数量计算
- ✅ 删除未使用的 S3 存储模块src/storage/s3/
- ✅ 修复 LLM 认证错误,使用 new_context() 初始化 Context
- ✅ 修复 Docker 环境空请求体错误,添加请求体验证
- 提供真实的多页作业图片进行完整流程测试
- 优化HTML报告的图片展示布局
- 支持PDF格式答案文档
@ -965,3 +967,97 @@ for future in concurrent.futures.as_completed(
- ✅ 兼容阿里云 CDN 等需要特殊 Headers 的服务
- ✅ 超时任务自动跳过,避免长时间阻塞
- ✅ 线上部署环境测试通过
## Docker 环境请求验证修复2026-03-30
### 问题诊断
在 Docker 环境中运行时报错:
```
Invalid JSON format: Expecting value: line 1 column 1 (char 0)
```
**原因分析**
1. 请求体为空(例如,使用 GET 请求而不是 POST
2. Content-Type 不是 application/json
3. 负载均衡器或代理可能过滤了请求体
### 解决方案
`http_run``http_stream_run` 函数中添加请求体验证:
```python
# 检查请求体是否为空
if not body_text or body_text.strip() == "":
logger.error(f"Empty request body for run_id={ctx.run_id}")
raise HTTPException(
status_code=400,
detail="Request body is empty. Please provide a valid JSON payload."
)
# 检查 Content-Type
content_type = request.headers.get("content-type", "")
if "application/json" not in content_type.lower():
logger.error(f"Invalid Content-Type: {content_type}")
raise HTTPException(
status_code=400,
detail=f"Content-Type must be 'application/json', got: {content_type}"
)
```
### 修改文件
- `src/main.py`
- `http_run` 函数:添加请求体验证
- `http_stream_run` 函数:添加请求体验证
### 正确的请求格式
**使用 curl**
```bash
curl -X POST http://localhost:8000/stream_run \
-H "Content-Type: application/json" \
-d '{
"student_homework": [
{
"student_id": 1,
"student_name": "张三",
"homework_images": ["https://example.com/image.jpg"]
}
],
"answer_doc_url": "",
"comment_max_length": 50,
"max_concurrent": 5
}'
```
**使用 Python requests**
```python
import requests
url = "http://localhost:8000/stream_run"
headers = {"Content-Type": "application/json"}
data = {
"student_homework": [
{
"student_id": 1,
"student_name": "张三",
"homework_images": ["https://example.com/image.jpg"]
}
],
"answer_doc_url": "",
"comment_max_length": 50,
"max_concurrent": 5
}
response = requests.post(url, json=data, headers=headers)
print(response.json())
```
**注意事项**
- ✅ 必须使用 POST 请求
- ✅ Content-Type 必须是 `application/json`
- ✅ 请求体必须是非空的 JSON 字符串
- ❌ 不要使用 GET 请求
- ❌ 不要发送空请求体
- ❌ 不要省略 Content-Type 头
### 效果
- ✅ 空请求体返回友好的错误信息
- ✅ 错误的 Content-Type 返回明确的错误提示
- ✅ 测试通过

View File

@ -251,6 +251,23 @@ async def http_run(request: Request) -> Dict[str, Any]:
body_text = str(raw_body)
raise HTTPException(status_code=400,
detail=f"Invalid JSON format: {body_text}, traceback: {traceback.format_exc()}, error: {e}")
# 检查请求体是否为空
if not body_text or body_text.strip() == "":
logger.error(f"Empty request body in http_run for run_id={ctx.run_id}")
raise HTTPException(
status_code=400,
detail="Request body is empty. Please provide a valid JSON payload."
)
# 检查 Content-Type
content_type = request.headers.get("content-type", "")
if "application/json" not in content_type.lower():
logger.error(f"Invalid Content-Type in http_run: {content_type}")
raise HTTPException(
status_code=400,
detail=f"Content-Type must be 'application/json', got: {content_type}"
)
ctx = new_context(method="run", headers=request.headers)
# 优先使用上游指定的 run_id保证 cancel 能精确匹配
@ -346,6 +363,24 @@ async def http_stream_run(request: Request):
body_text = str(raw_body)
raise HTTPException(status_code=400,
detail=f"Invalid JSON format: {body_text}, traceback: {extract_core_stack()}, error: {e}")
# 检查请求体是否为空
if not body_text or body_text.strip() == "":
logger.error(f"Empty request body in http_stream_run for run_id={ctx.run_id}")
raise HTTPException(
status_code=400,
detail="Request body is empty. Please provide a valid JSON payload."
)
# 检查 Content-Type
content_type = request.headers.get("content-type", "")
if "application/json" not in content_type.lower():
logger.error(f"Invalid Content-Type in http_stream_run: {content_type}")
raise HTTPException(
status_code=400,
detail=f"Content-Type must be 'application/json', got: {content_type}"
)
run_id = ctx.run_id
is_agent = graph_helper.is_agent_proj()
logger.info(