chore: enhance the hint when the user triggers an invalid webhook request (#28671)

This commit is contained in:
非法操作 2025-11-26 14:00:16 +08:00 committed by GitHub
parent 490b7ac43c
commit 1241cab113
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 46 additions and 13 deletions

View File

@ -1,7 +1,7 @@
import logging
import time
from flask import jsonify
from flask import jsonify, request
from werkzeug.exceptions import NotFound, RequestEntityTooLarge
from controllers.trigger import bp
@ -28,8 +28,14 @@ def _prepare_webhook_execution(webhook_id: str, is_debug: bool = False):
webhook_data = WebhookService.extract_and_validate_webhook_data(webhook_trigger, node_config)
return webhook_trigger, workflow, node_config, webhook_data, None
except ValueError as e:
# Fall back to raw extraction for error reporting
webhook_data = WebhookService.extract_webhook_data(webhook_trigger)
# Provide minimal context for error reporting without risking another parse failure
webhook_data = {
"method": request.method,
"headers": dict(request.headers),
"query_params": dict(request.args),
"body": {},
"files": {},
}
return webhook_trigger, workflow, node_config, webhook_data, str(e)

View File

@ -5,6 +5,7 @@ import secrets
from collections.abc import Mapping
from typing import Any
import orjson
from flask import request
from pydantic import BaseModel
from sqlalchemy import select
@ -169,7 +170,7 @@ class WebhookService:
- method: HTTP method
- headers: Request headers
- query_params: Query parameters as strings
- body: Request body (varies by content type)
- body: Request body (varies by content type; JSON parsing errors raise ValueError)
- files: Uploaded files (if any)
"""
cls._validate_content_length()
@ -255,14 +256,21 @@ class WebhookService:
Returns:
tuple: (body_data, files_data) where:
- body_data: Parsed JSON content or empty dict if parsing fails
- body_data: Parsed JSON content
- files_data: Empty dict (JSON requests don't contain files)
Raises:
ValueError: If JSON parsing fails
"""
raw_body = request.get_data(cache=True)
if not raw_body or raw_body.strip() == b"":
return {}, {}
try:
body = request.get_json() or {}
except Exception:
logger.warning("Failed to parse JSON body")
body = {}
body = orjson.loads(raw_body)
except orjson.JSONDecodeError as exc:
logger.warning("Failed to parse JSON body: %s", exc)
raise ValueError(f"Invalid JSON body: {exc}") from exc
return body, {}
@classmethod

View File

@ -118,10 +118,8 @@ class TestWebhookServiceUnit:
"/webhook", method="POST", headers={"Content-Type": "application/json"}, data="invalid json"
):
webhook_trigger = MagicMock()
webhook_data = WebhookService.extract_webhook_data(webhook_trigger)
assert webhook_data["method"] == "POST"
assert webhook_data["body"] == {} # Should default to empty dict
with pytest.raises(ValueError, match="Invalid JSON body"):
WebhookService.extract_webhook_data(webhook_trigger)
def test_generate_webhook_response_default(self):
"""Test webhook response generation with default values."""
@ -435,6 +433,27 @@ class TestWebhookServiceUnit:
assert result["body"]["message"] == "hello" # Already string
assert result["body"]["age"] == 25 # Already number
def test_extract_and_validate_webhook_data_invalid_json_error(self):
"""Invalid JSON should bubble up as a ValueError with details."""
app = Flask(__name__)
with app.test_request_context(
"/webhook",
method="POST",
headers={"Content-Type": "application/json"},
data='{"invalid": }',
):
webhook_trigger = MagicMock()
node_config = {
"data": {
"method": "post",
"content_type": "application/json",
}
}
with pytest.raises(ValueError, match="Invalid JSON body"):
WebhookService.extract_and_validate_webhook_data(webhook_trigger, node_config)
def test_extract_and_validate_webhook_data_validation_error(self):
"""Test unified data extraction with validation error."""
app = Flask(__name__)