使用Python标准库http.client发送POST form-data失败,提示emailContent不存在
问题:使用http.client发送form-data时提示'emailContent'不存在(400错误)
系统无法安装requests等第三方库,只能依赖Python标准库http.client发送multipart/form-data请求,但调用接口后持续收到400错误,提示'emailContent'不存在。
原代码
import http.client import uuid def send_email_http_only(from_email, reply_to, send_to, subject, mail_content, filename, attachment_path): # Prepare the file content file_path = attachment_path with open(file_path, "rb") as f: file_content = f.read() # Define boundary and headers boundary = str(uuid.uuid4()) headers = { "User-Agent": f"MyApp/1.0", "Content-Type": f"multipart/form-data; boundary=----{boundary}", } # Create HTTP connection conn = http.client.HTTPConnection("localhost", 8088) # Create multipart/form-data payload payload = ( # f"----{boundary}\r\n" # f"Content-Disposition: form-data; name=\"attachment\"; filename=\"" + filename + "\"\r\n" # f"{file_content.decode('utf-8')}\r\n" f"----{boundary}\r\n" f"Content-Disposition: form-data; name=\"emailContent\"\r\n" f"Content-Type: application/json\r\n\r\n" f"{{\"replyTo\": \"{reply_to}\", \"from\": \"{from_email}\", \"sendTo\": \"{send_to}\", \"subject\": \"{subject}\", \"mailContent\": \"{mail_content}\"}}\r\n" f"----{boundary}--\r\n" ) emailContent = { 'replyTo': reply_to, 'from': from_email, 'sendTo': send_to, 'subject': subject, 'mailContent': mail_content } # print(f"request_data: {request_data}") # print(f"payload: {payload}") # print(f"headers: {headers}") # Send the request conn.request("POST", "/sendEmail", body=payload, headers=headers) # Get the response response = conn.getresponse() data = response.read() # Close the connection conn.close() # Print response print("Program response:") print(response.status, response.reason) print(data.decode("utf-8"))
调试输出
send: b'POST /sendEmail HTTP/1.1\r\nHost: localhost:8088\r\nAccept-Encoding: identity\r\nContent-Length: 340\r\nUser-Agent: MyApp/1.0\r\nContent-Type: multipart/form-data; boundary=----18e9255e-7597-42ef-814f-f10b4f0a2c6e\r\n\r\n' send: b'----18e9255e-7597-42ef-814f-f10b4f0a2c6e\r\nContent-Disposition: form-data; name="emailContent"\r\nContent-Type: application/json\r\n\r\n{"replyTo": "x@gmail.com", "from": "y@outlook.com", "sendTo": "y@outlook.com", "subject": "Test subject", "mailContent": "Test main content"}\r\n----18e9255e-7597-42ef-814f-f10b4f0a2c6e--\r\n' reply: 'HTTP/1.1 400 \r\n'
问题原因及解决方法
1. Boundary格式不符合RFC规范
根据multipart/form-data的RFC标准,请求头中的boundary值是分隔符的核心标识,实际分隔线需要在boundary值前加两个连字符--。原代码中:
- 请求头的
boundary设置为----{uuid} - payload中的分隔线直接用
----{uuid}
这导致服务端无法正确识别multipart的各个分段,因此找不到emailContent字段。
修正方式:
- 请求头中
boundary直接使用uuid值 - payload中的分隔线改为
--{uuid},结束线改为--{uuid}--
2. 手动拼接JSON易出错
原代码手动拼接JSON字符串,若内容包含双引号、换行等特殊字符,会破坏JSON结构,导致服务端无法解析字段。应该用json模块生成标准JSON。
3. 字符串payload存在编码风险
直接用字符串作为请求体,若包含非ASCII字符,会因编码问题导致数据损坏,应构建bytes类型的payload。
修正后的代码
import http.client import uuid import json def send_email_http_only(from_email, reply_to, send_to, subject, mail_content, filename, attachment_path): # 读取附件内容(如果需要添加附件) file_content = b'' if attachment_path: with open(attachment_path, "rb") as f: file_content = f.read() # 定义boundary和请求头 boundary = str(uuid.uuid4()) headers = { "User-Agent": "MyApp/1.0", "Content-Type": f"multipart/form-data; boundary={boundary}", } # 创建HTTP连接 conn = http.client.HTTPConnection("localhost", 8088) # 构建bytes类型的payload payload = b'' # 添加emailContent字段(JSON格式) payload += f"--{boundary}\r\n".encode('utf-8') payload += b'Content-Disposition: form-data; name="emailContent"\r\n' payload += b'Content-Type: application/json\r\n\r\n' email_content_dict = { 'replyTo': reply_to, 'from': from_email, 'sendTo': send_to, 'subject': subject, 'mailContent': mail_content } payload += json.dumps(email_content_dict).encode('utf-8') payload += b'\r\n' # 添加附件(如果需要,取消注释) # if file_content: # payload += f"--{boundary}\r\n".encode('utf-8') # payload += f'Content-Disposition: form-data; name="attachment"; filename="{filename}"\r\n'.encode('utf-8') # payload += b'Content-Type: application/octet-stream\r\n\r\n' # payload += file_content # payload += b'\r\n' # 结束分隔线 payload += f"--{boundary}--\r\n".encode('utf-8') # 发送请求 conn.request("POST", "/sendEmail", body=payload, headers=headers) # 获取响应 response = conn.getresponse() data = response.read() # 关闭连接 conn.close() # 打印响应 print("Program response:") print(response.status, response.reason) print(data.decode("utf-8"))
内容的提问来源于stack exchange,提问作者Eugene
相关产品推荐
相关产品推荐

