在Python中解析多部分请求字符串

时间:2018-06-19 09:36:18

标签: python aws-lambda aws-api-gateway

我有一个像这样的字符串

"--5b34210d81fb44c5a0fdc1a1e5ce42c3\r\nContent-Disposition: form-data; name=\"author\"\r\n\r\nJohn Smith\r\n--5b34210d81fb44c5a0fdc1a1e5ce42c3\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example2.txt\"\r\nContent-Type: text/plain\r\nExpires: 0\r\n\r\nHello World\r\n--5b34210d81fb44c5a0fdc1a1e5ce42c3--\r\n"

我也有其他可用的请求标题。

如何使用Python3轻松解析它?

我正在通过API网关处理AWS Lambda中的文件上传,请求正文和标题可通过Python dicts获得。

stackoverflow还有其他类似的问题,但大多数都假设使用requests模块或其他模块,并期望请求详细信息为特定对象或格式。

注意:我知道可以将用户上传到S3并触发Lambda,但在这种情况下我有意选择不这样做。

5 个答案:

答案 0 :(得分:4)

可以使用类似的方法来解析

from requests_toolbelt.multipart import decoder
multipart_string = "--ce560532019a77d83195f9e9873e16a1\r\nContent-Disposition: form-data; name=\"author\"\r\n\r\nJohn Smith\r\n--ce560532019a77d83195f9e9873e16a1\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example2.txt\"\r\nContent-Type: text/plain\r\nExpires: 0\r\n\r\nHello World\r\n--ce560532019a77d83195f9e9873e16a1--\r\n"
content_type = "multipart/form-data; boundary=ce560532019a77d83195f9e9873e16a1"
decoder.MultipartDecoder(multipart_string, content_type)

答案 1 :(得分:1)

扩展sam-anthony的答案(我必须对其进行一些修复才能在python 3.6.8上运行):

from requests_toolbelt.multipart import decoder

multipart_string = b"--ce560532019a77d83195f9e9873e16a1\r\nContent-Disposition: form-data; name=\"author\"\r\n\r\nJohn Smith\r\n--ce560532019a77d83195f9e9873e16a1\r\nContent-Disposition: form-data; name=\"file\"; filename=\"example2.txt\"\r\nContent-Type: text/plain\r\nExpires: 0\r\n\r\nHello World\r\n--ce560532019a77d83195f9e9873e16a1--\r\n"
content_type = "multipart/form-data; boundary=ce560532019a77d83195f9e9873e16a1"

for part in decoder.MultipartDecoder(multipart_string, content_type).parts:
  print(part.text)

John Smith
Hello World

您需要做的是通过 pip install requests-toolbelt -target =。安装此库,然后将其与lambda脚本一起上传

这是一个可行的示例:

from requests_toolbelt.multipart import decoder

def lambda_handler(event, context):

    content_type_header = event['headers']['Content-Type']

    body = event["body"].encode()

    response = ''
    for part in decoder.MultipartDecoder(body, content_type_header).parts:
      response += part.text + "\n"

    return {
        'statusCode': 200,
        'body': response
    }

答案 2 :(得分:1)

api网关有很多奇怪的编码问题,还有奇怪的行为,最初以字节为单位接收请求的主体,然后重新部署后开始将它们接收为base64。无论如何,这是最终为我工作的代码。

import json
import base64
import boto3
from requests_toolbelt.multipart import decoder

s3client = boto3.client("s3")
def lambda_handler(event, context):
    content_type_header = event['headers']['content-type']
    postdata = base64.b64decode(event['body']).decode('iso-8859-1')
    imgInput = ''
    lst = []
    for part in decoder.MultipartDecoder(postdata.encode('utf-8'), content_type_header).parts:
        lst.append(part.text)
    response = s3client.put_object(  Body=lst[0].encode('iso-8859-1'),  Bucket='test',    Key='mypicturefinal.jpg')
    return {'statusCode': '200','body': 'Success', 'headers': { 'Content-Type': 'text/html' }}

答案 3 :(得分:0)

如果您想使用Python的CGI,

from cgi import parse_multipart
from io import BytesIO

c_type, c_data = parse_header(event['headers']['Content-Type'])
assert c_type == 'multipart/form-data'
decoded_string = base64.b64decode(event['body'])
form_data = parse_multipart(BytesIO(decoded_string), c_data)

for image_str in form_data['file']:
    ...

答案 4 :(得分:0)

如果使用CGI,我建议使用FieldStorage:

template<typename ...Types>
        ECSViewTest<Types...> View()
        {

            //works
            ECSViewTest<Types...> view;

            //cant figure out how the go over the types
            foreach(template Type arg in Types...){

                Get All Entities who have this component type
            }

        //usage
        ECSViewTest<TransformComponent, MeshComponent> view = entityManager.View<TransformComponent, MeshComponent>();

另请参阅: https://stackoverflow.com/a/38718958/10913265

如果事件正文包含多个文件:

from cgi import FieldStorage

fs = FieldStorage(fp=event['body'], headers=event['headers'], environ={'REQUEST_METHOD':'POST', 'CONTENT_TYPE':event['headers']['Content-Type'], })['file']
originalFileName = fs.filename
binaryFileData = fs.file.read()

提供FieldStorage对象的列表。因此,您可以这样做:

fs = FieldStorage(fp=event['body'], headers=event['headers'], environ={'REQUEST_METHOD':'POST', 'CONTENT_TYPE':event['headers']['Content-Type'], })['file']

我用于处理单个文件以及多个文件以及包含无文件的正文的解决方案是 mutlipart / form-data

for f in fs:
    originalFileName = f.filename
    binaryFileData = f.file.read()