chore: (trigger)change content type from form to application/octet-stream (#25167)

This commit is contained in:
非法操作 2025-09-05 09:54:07 +08:00 committed by GitHub
parent eab03e63d4
commit d8f6f9ce19
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 48 additions and 28 deletions

View File

@ -21,7 +21,7 @@ class ContentType(StrEnum):
FORM_DATA = "multipart/form-data"
FORM_URLENCODED = "application/x-www-form-urlencoded"
TEXT = "text/plain"
FORM = "form"
BINARY = "application/octet-stream"
class WebhookParameter(BaseModel):

View File

@ -108,6 +108,9 @@ class TriggerWebhookNode(BaseNode):
# For text/plain, the entire body is a single string parameter
outputs[param_name] = str(webhook_data.get("body", {}).get("raw", ""))
continue
elif self._node_data.content_type == ContentType.BINARY:
outputs[param_name] = webhook_data.get("body", {}).get("raw", b"")
continue
if param_type == "file":
# Get File object (already processed by webhook controller)

View File

@ -97,12 +97,45 @@ class WebhookService:
# Handle file uploads
if request.files:
data["files"] = cls._process_file_uploads(request.files, webhook_trigger)
else:
# Raw text data
elif "application/octet-stream" in content_type:
# Binary data - process as file using ToolFileManager
try:
file_content = request.get_data()
if file_content:
tool_file_manager = ToolFileManager()
# Create file using ToolFileManager
tool_file = tool_file_manager.create_file_by_raw(
user_id=webhook_trigger.created_by,
tenant_id=webhook_trigger.tenant_id,
conversation_id=None,
file_binary=file_content,
mimetype="application/octet-stream",
)
# Build File object
mapping = {
"tool_file_id": tool_file.id,
"transfer_method": FileTransferMethod.TOOL_FILE.value,
}
file_obj = file_factory.build_from_mapping(
mapping=mapping,
tenant_id=webhook_trigger.tenant_id,
)
data["body"] = {"raw": file_obj.to_dict()}
else:
data["body"] = {"raw": None}
except Exception:
logger.exception("Failed to process octet-stream data")
data["body"] = {"raw": None}
elif "text/plain" in content_type:
# Text data - store as raw string
try:
data["body"] = {"raw": request.get_data(as_text=True)}
except Exception:
data["body"] = {"raw": ""}
else:
raise ValueError(f"Unsupported Content-Type: {content_type}")
return data
@ -275,25 +308,7 @@ class WebhookService:
return validation_result
else:
# For other unsupported content types, only validate existence of required parameters
body_params = node_data.get("body", [])
for body_param in body_params:
param_name = body_param.get("name", "")
param_type = body_param.get("type", SegmentType.STRING)
is_required = body_param.get("required", False)
if not is_required:
continue
# Check if parameter exists
if param_type == SegmentType.FILE:
file_obj = webhook_data.get("files", {}).get(param_name)
if not file_obj:
return {"valid": False, "error": f"Required file parameter missing: {param_name}"}
else:
body_data = webhook_data.get("body", {})
if param_name not in body_data:
return {"valid": False, "error": f"Required body parameter missing: {param_name}"}
raise ValueError(f"Unsupported Content-Type for validation: {configured_content_type}")
return {"valid": True}

View File

@ -78,17 +78,19 @@ const ParameterTable: FC<ParameterTableProps> = ({
const handleDataChange = (data: GenericTableRow[]) => {
// For text/plain, enforce single text body semantics: keep only first non-empty row and force string type
// For application/octet-stream, enforce single file body semantics: keep only first non-empty row and force file type
const isTextPlain = isRequestBody && (contentType || '').toLowerCase() === 'text/plain'
const isOctetStream = isRequestBody && (contentType || '').toLowerCase() === 'application/octet-stream'
const normalized = data
.filter(row => typeof row.key === 'string' && (row.key as string).trim() !== '')
.map(row => ({
name: String(row.key),
type: isTextPlain ? VarType.string : normalizeParameterType((row.type as string)),
type: isTextPlain ? VarType.string : isOctetStream ? VarType.file : normalizeParameterType((row.type as string)),
required: Boolean(row.required),
}))
const newParams: WebhookParameter[] = isTextPlain
const newParams: WebhookParameter[] = (isTextPlain || isOctetStream)
? normalized.slice(0, 1)
: normalized

View File

@ -32,7 +32,7 @@ const CONTENT_TYPES = [
{ name: 'application/json', value: 'application/json' },
{ name: 'application/x-www-form-urlencoded', value: 'application/x-www-form-urlencoded' },
{ name: 'text/plain', value: 'text/plain' },
{ name: 'forms', value: 'forms' },
{ name: 'application/octet-stream', value: 'application/octet-stream' },
{ name: 'multipart/form-data', value: 'multipart/form-data' },
]

View File

@ -42,9 +42,9 @@ const CONTENT_TYPE_CONFIGS = {
supportedTypes: [VarType.string, VarType.number, VarType.boolean] as const,
description: 'Form data supports basic types',
},
'forms': {
supportedTypes: [VarType.string, VarType.number, VarType.boolean] as const,
description: 'Form data supports basic types',
'application/octet-stream': {
supportedTypes: [VarType.file] as const,
description: 'octet-stream supports only binary data',
},
'multipart/form-data': {
supportedTypes: [VarType.string, VarType.number, VarType.boolean, VarType.file] as const,