zoukankan      html  css  js  c++  java
  • 解决python发送multipart/form-data请求上传文件的问题

    服务器接收文件时,有时会使用表单接收的方式,这意味着我们需要使用Python的requests上传表单数据和文件。

    常用的方式一般如下:

    data = {
        'name': 'nginx'
    }
    files = {'file': open("abc.csv", 'rb')}
    
    response = requests.post(url, data=data, files=files)
    

      files是封装好的参数,直接包括了文件内容,文件名,格式等,data则是表单内容,但这样做有一个问题,文件是中文名时,requests就会报错,哪怕encode转码成utf8也没用

    百度发现除了requests的这个方法,还可以用一个第三方包MultipartEncoder,而这个包相对来说比较灵活。

    一般是from requests_toolbelt.multipart.encoder import MultipartEncoder,这样导入使用

    由于公司项目需要兼容各种环境,不主张使用大量第三方库,我精简模块后提取出my_compat 文件,变成 from my_compat import MultipartEncoder这样导入使用

    但MultipartEncoder也存在无法转化中文名的问题,所以我在代码里取了巧,先把文件名转化成可解析的字符,然后用to_string方法解析,最后把解析后的字符串转化回去

    from requests_toolbelt.multipart.encoder import MultipartEncoder
    from my_compat import MultipartEncoder
    import urllib
    import requests
    import json
    
    
    encoded_name = urllib.quote(file_name.encode('utf-8'))//取巧做法,先转化字符
    with open(res_path, 'rb') as f_:
        m = MultipartEncoder(
            fields={'file': (encoded_name, f_,
                             'application/octet-stream')}
        )
    
        decoded_m = m.to_string()//解析时不支持中文
        decoded_m = decoded_m.replace(encoded_name, file_name)//替代转化
        response = requests.post(url,
                                 data=decoded_m,
                                 headers={'Content-Type': m.content_type,
                                          'charset': 'UTF-8'},
                                 verify=False)
    
        try:
            content = json.loads(response.content)
        except ValueError:
            content = response.content
        return content, response.status_code
    

      后来发现这样做其实很不方便,所以我就阅读MultipartEncoder的源码,发现content_type其实就是一个很简单的随机字符串的构造,而数据的字符流只要符合一定规范就可以构造,再结合requests包,写出了如下的代码,

    #coding=utf8
    import requests
    from uuid import uuid4
    import os
    
    file_name='test'
    url=
    
    boundary=uuid4().hex
    header={'Content-Type': 'multipart/form-data; boundary={0}'.format(boundary),'charset': 'UTF-8'}
    with open(r'C:	est'.decode('utf8'), 'r') as f:
        content=f.readlines()
        print content
        content=''.join(content)
        datas = '--{0}{1}Content-Disposition: form-data; name="file"; filename="{2}"{1}Content-Type: application/octet-stream{1}{1}{3}{1}--{0}--{1}'. 
            format(boundary,os.linesep, file_name, content,boundary)
        print repr(datas)
        print header
        response = requests.post(url,
                                 data=datas,
                                 headers=header,
                                 verify=False)
        print response.status_code,response.text
    

    在windows上调试可以,但在linux上调试一直报错,后来把os.linesep换成指定的' '分隔符就可以成功了,不知道是我们公司服务器设置问题还是这个库的解析问题。  

    #coding=utf8
    import requests
    from uuid import uuid4
    import os
    
    file_name='test'
    url=
    
    boundary=uuid4().hex
    header={'Content-Type': 'multipart/form-data; boundary={0}'.format(boundary),'charset': 'UTF-8'}
    with open(r'C:	est'.decode('utf8'), 'r') as f:
        content=f.readlines()
        print content
        content=''.join(content)
        datas = '--{0}{1}Content-Disposition: form-data; name="file"; filename="{2}"{1}Content-Type: application/octet-stream{1}{1}{3}{1}--{0}--{1}'. 
            format(boundary,'
    ', file_name, content,boundary)
        print repr(datas)
        print header
        response = requests.post(url,
                                 data=datas,
                                 headers=header,
                                 verify=False)
        print response.status_code,response.text

    结合saltstack,在proxy上执行的 "salt '{}' cp.push {}".format(path, agent_id, file_path)命令,效果更佳

  • 相关阅读:
    不同浏览器对于js中for循环的判断
    png格式图片背景不透明问题解决
    qq登陆错误提示
    T职场人生系列之二十四:程序员如何增加收入
    if [ $# eq 0 ]该语句是什么含义?
    动态IP修改注册表降低PING值教程(XP系统)
    c# List列表数据转换成树形结构
    net core EF 链接mysql 数据库
    net core 部署到windows 服务
    IdentityServer4 密码模式认证
  • 原文地址:https://www.cnblogs.com/slqt/p/10238019.html
Copyright © 2011-2022 走看看