Запросы Python — ошибка извлечения из S3 в составную часть

#python #amazon-web-services #aws-lambda #python-requests #multipart

#python #amazon-web-services #aws-lambda #python-запросы #multipart

Вопрос:

Привет, пытаясь извлечь файл из S3 и передать его в конечную точку multipart post в другой службе, код выглядит примерно так

 def execute(event, context):
    if "emailId" in event:
        props = {
            "fieldOne": "someValue",
            "fieldTwo": "someOtherValue",
            "contentType": "eml"
        }
        props = json.dumps(props)
        file = download_s3_file_to_tmp(event["emailId"])
        multipart_request(props, file, event["emailId"])


def download_s3_file_to_tmp(message_id):
    s3_key = "".join([_email_bucket_folder_name, "/", str(message_id), ".eml"])
    s3_client = boto3.client("s3", _region)
    s3_client.download_file(_my_bucket, s3_key, "/tmp/" str(message_id) ".eml")
    downloaded_eml_file = open("/tmp/" str(message_id) ".eml", 'rb')
    return downloaded_eml_file

def multipart_request(props, file_content, message_id):
    my_id = *****
    secret = *****
    url = f"{_url}/...."
    payload = {"props": props}
    files = [{"fileContent", file_content}]
    tmp_file_path = "/tmp/" message_id ".eml"
    if os.path.exists(tmp_file_path):
        os.remove(tmp_file_path)
        print("Removed the file %s" % tmp_file_path)     
    else:
        print("File %s does not exist." % tmp_file_path)
    LOGGER.info(f"payload: {payload}")
    resp = requests.post(url,data=payload,files=files,auth=requests.auth.HTTPBasicAuth(my_id, secret))
    LOGGER.info(f"Request Headers: {resp.request.headers}")
    return resp.status_code, resp.text, filenote_id
 

Проблема в том (при тестировании с одним и тем же файлом из корзины S3, поэтому там не должно быть несоответствий), что периодически я получаю сообщение об ошибке

   "errorMessage": "expected string or bytes-like object",
  "errorType": "TypeError",
 

при вызове requests.post. Иногда это нормально, я получаю 200, но много времени я получаю вышеуказанную ошибку.

вот трассировка стека, касающаяся модуля запросов

 {
  "errorMessage": "expected string or bytes-like object",
  "errorType": "TypeError",
  "stackTrace": [
    "  File "/var/task/my_lambda.py", line 42, in executen    multipart_request(props, file, event["emailId"])n",
    "  File "/var/task/mime_retrieval_parser.py", line 75, in multipart_requestn    resp = requests.post(url,data=payload,files=files,auth=requests.auth.HTTPBasicAuth(edm_id, edm_secret))n",
    "  File "/opt/python/requests/api.py", line 119, in postn    return request('post', url, data=data, json=json, **kwargs)n",
    "  File "/opt/python/requests/api.py", line 61, in requestn    return session.request(method=method, url=url, **kwargs)n",
    "  File "/opt/python/requests/sessions.py", line 516, in requestn    prep = self.prepare_request(req)n",
    "  File "/opt/python/requests/sessions.py", line 449, in prepare_requestn    p.prepare(n",
    "  File "/opt/python/requests/models.py", line 317, in preparen    self.prepare_body(data, files, json)n",
    "  File "/opt/python/requests/models.py", line 505, in prepare_bodyn    (body, content_type) = self._encode_files(files, data)n",
    "  File "/opt/python/requests/models.py", line 166, in _encode_filesn    rf.make_multipart(content_type=ft)n",
    "  File "/opt/python/urllib3/fields.py", line 267, in make_multipartn    self._render_parts(n",
    "  File "/opt/python/urllib3/fields.py", line 225, in _render_partsn    parts.append(self._render_part(name, value))n",
    "  File "/opt/python/urllib3/fields.py", line 205, in _render_partn    return self.header_formatter(name, value)n",
    "  File "/opt/python/urllib3/fields.py", line 116, in format_header_param_html5n    value = _replace_multiple(value, _HTML5_REPLACEMENTS)n",
    "  File "/opt/python/urllib3/fields.py", line 89, in _replace_multiplen    result = pattern.sub(replacer, value)n"
  ]
}
 

Комментарии:

1. Пожалуйста, укажите всю трассировку стека в вашем вопросе. В противном случае нам придется визуально сканировать ваш код, чтобы идентифицировать строку. Конечно, мы можем искать » requests.post вызов». Но вы не должны ожидать, что люди будут тратить на это время, если вы хотите, чтобы они вам помогли.

2. Я не включил, потому что я обновил имена своих функций для вопроса. Исходные связаны с моей работой, поэтому я не хочу публиковать их на SO. Я вскоре отредактирую трассировку с новыми составными именами и обновлю вопрос, но буквально всего в 2 строках говорится, что это происходит в запросе post.

Ответ №1:

Решаемая проблема с помощью приведенного ниже подхода

 def execute(event, context):
    if "emailId" in event:
        props = {
            "fieldOne": "someValue",
            "fieldTwo": "someOtherValue",
            "contentType": "eml"
        }
        tmp_file_path = "/tmp/"   message_id   ".eml"
        props = json.dumps(props)
        file = download_s3_file_to_tmp(event["emailId"])
        multipart_request(props, file, tmp_file_path)

def download_s3_file_to_tmp(message_id, tmp_file_path):
    s3_key = "".join([_bucket_folder_name, "/", str(message_id), ".eml"])
    s3_client.download_file(
        _my_bucket, s3_key, "/tmp/"   str(message_id)   ".eml"
    )
    return open(tmp_file_path).read()

def multipart_request(props, opened_eml_file, tmp_file_path):
    my_id = *****
    secret = *****
    url = f"{_url}/...."
    payload = {"props": props}
    files = {"fileContent": ("whatEverYouWantToNameFile.eml", opened_eml_file)}

    if os.path.exists(tmp_file_path):
        os.remove(tmp_file_path)
        print("Removed the file %s" % tmp_file_path)     
    else:
        print("File %s does not exist." % tmp_file_path)

    resp = requests.post(url,data=payload,files=files,auth=requests.auth.HTTPBasicAuth(my_id, secret))
    return resp.status_code, resp.text, filenote_id