使用multipart/form-data数据格式传输pdf文件

本文介绍了一种通过HTTP POST请求上传PDF文件的方法。该方法首先将PDF文件转换为字节流,然后使用multipart/form-data格式进行传输。文章提供了一个具体的Java实现示例,包括如何从指定路径读取文件并发送到服务器。

http协议下载pdf文件字节后,使用multipart/form-data数据格式传输至指定url


/**
     * 根据pdf文件下载路径以post方式上传至服务器(出参数据格式为json)
     *
     * @param url       url地址
     * @param fileName  文件名
     * @param fileRoute 文件下载路径
     * @return 响应的结果
     */
    public static String sendPostWithPdf(String url, String fileName, String fileRoute) {
        PostMethod post = null;
        //接受响应回来的文本
        String returnText = "{\"errcode\":1,\"errmsg\":\"上传文件失败\"}";
        InputStream input = null;
        byte[] bytes = null;
        try {
            URL filrUrl = new URL(fileRoute);
            URLConnection urlConn = filrUrl.openConnection();
            int length = urlConn.getContentLength();
            if (length > 0) {
                bytes = new byte[length];
                input = urlConn.getInputStream();
                //根据文件下载路径,存为字节
                int str = input.read(bytes);
            } else {
                log.error("ftp文件内容为空");
            }
        } catch (Exception e) {
            log.error("下载ftp文件失败" + e.getMessage());
        }
        try {
            HttpClient client = new HttpClient();
            //登录
            post = new PostMethod(url);
            //设置字节文件
            ByteArrayPartSource byteArrayPartSource = new ByteArrayPartSource(fileName, bytes);
            //不需要下载时,可省略前面的步骤,直接new File("")
//            FilePart fp = new FilePart(fileName, new File("D:\\test.pdf"));
            FilePart fp = new FilePart(fileName, byteArrayPartSource);
            fp.setCharSet("utf-8");
            //设置传输文件类型类型
            fp.setContentType("application/octet-stream");
            fp.setName("pdf");
            Part[] parts = {fp};
            //使用multipart/form-data数据格式传输
            MultipartRequestEntity entity = new MultipartRequestEntity(parts, new HttpMethodParams());
            post.setRequestEntity(entity);
            client.executeMethod(post);
            returnText = post.getResponseBodyAsString();
        } catch (IOException e) {
            log.error("上传pdf文件出错:" + e.getMessage());
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        //使用finally块来关闭输出流、输入流
        finally {
            if (post != null) {
                post.releaseConnection();
            }
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return returnText;
    }

<think>嗯,用户现在的问题是关于在Python中使用multipart/form-data格式同时上传参数和文件时遇到的ASCII字符错误。他们之前已经遇到了ValueError,提示字符串参数只能包含ASCII字符。现在他们想了解如何解决这个问题,同时正确地上传参数和文件。首先,我需要回顾之前的对话。用户之前的问题是关于处理加密后的参数导致非ASCII字符的错误,解决方案是使用Base64编码。现在他们的问题更具体,涉及到multipart/form-data上传,同时处理参数和文件,并且避免ASCII错误。根据用户提供的引用,特别是引用[1]中的代码示例,他们尝试使用requests_toolbelt的MultipartEncoder来处理文件上传,但可能没有正确编码参数。用户可能在将参数(比如加密后的数据)添加到表单数据时,没有正确转换为ASCII字符串,导致包含非ASCII字符,从而引发ValueError。接下来,我需要考虑如何正确构造multipart/form-data请求,同时确保所有参数都是ASCII字符。可能的解决方案包括: 1.确保所有文本参数都经过Base64编码或其他ASCII安全编码处理。2.使用requests_toolbelt的MultipartEncoder来正确构建表单数据,包括文件和参数。 3.验证每个参数是否为字符串类型且仅包含ASCII字符,避免直接传递字节类型。另外,用户可能在使用json.dumps时没有设置ensure_ascii=False,导致非ASCII字符被转义,但之后加密后的数据如果没有正确编码,仍然可能包含非ASCII字符。例如,加密后的二进制数据如果直接转为字符串,可能会有非ASCII字节,这时候必须用Base64编码转换为ASCII字符串。还需要检查用户是否正确处理了加密后的数据。比如,加密后的字节是否经过Base64编码并解码为ASCII字符串。如果用户直接使用str(encrypted_bytes),这会导致表示字节的字符串包含非ASCII字符,如\x80等,从而引发错误。 因此,正确的步骤应该是: 1.对需要上传的参数进行加密,并将加密后的二进制数据使用Base64编码,然后解码为ASCII字符串。 2.使用MultipartEncoder将文件和参数组合成表单数据,确保所有文本参数都是ASCII字符串。3.在构建请求时,设置正确的Content-Type头部,由MultipartEncoder自动处理。同时,用户可能需要安装requests_toolbelt库,并正确导入MultipartEncoder。在代码示例中,用户引用了该库,但需要确认是否正确使用,比如是否将参数和文件都放入MultipartEncoder的字段中。 最后,需要添加验证步骤,确保所有文本参数不含非ASCII字符,比如使用字符串的isascii()方法进行检查,或者在构造表单数据前进行断言,避免运行时错误。</think>### 解决方案:Python实现multipart/form-data同时上传参数和文件并避免ASCII错误 #### 一、核心问题定位 当使用`multipart/form-data`格式同时上传文件和非ASCII参数时,需严格遵循: 1. 文本参数必须为ASCII字符串 2. 文件参数使用二进制模式读取 3. 请求体构造必须符合RFC 2046规范[^1] #### 二、分步解决方案 ##### 1. 参数预处理(解决ASCII错误) $$ \text{Base64}( \text{AES\_Encrypt}( \text{UTF-8}( \text{JSON} )) ) $$ ```python import base64 import json from Crypto.Cipher import AES def prepare_params(data_dict: dict, key: bytes) -> str: # 处理非ASCII文本参数 json_str = json.dumps(data_dict, ensure_ascii=False).encode('utf-8') cipher = AES.new(key, AES.MODE_CBC, iv=b'1234567890123456') padded = pad(json_str, AES.block_size) encrypted = cipher.encrypt(padded) return base64.b64encode(encrypted).decode('ascii') # 强制转为ASCII[^2] ``` ##### 2. 构建混合表单数据 ```python from requests_toolbelt import MultipartEncoder def build_multipart(file_path: str, params: dict): with open(file_path, 'rb') as f: return MultipartEncoder( fields={ 'file': (os.path.basename(file_path), f, 'application/octet-stream'), **{k: str(v) for k, v in params.items()} # 强制所有参数转为字符串 } ) ``` ##### 3. 发送请求 ```python import requests def upload_data(url: str, encoder: MultipartEncoder): headers = {'Content-Type': encoder.content_type} response = requests.post(url, data=encoder, headers=headers) return response.json() ``` #### 三、完整调用示例 ```python # 加密参数示例 params = {'user': '张三', 'data': '重要数据'} encrypted_params = prepare_params(params, key=b'32byteslongsecretkey1234567890') # 构建混合表单 encoder = build_multipart('/data/test.pdf', {'params': encrypted_params}) # 发送请求 result = upload_data('https://api.example.com/upload', encoder) print(f"上传结果:{result}") ``` ### 关键验证点 | 验证项 | 验证方法 | 预期结果 | |------------------------|------------------------------|---------------------| | 参数编码类型 | `print(type(encrypted_params))` | `<class 'str'>` | | ASCII字符集合规性 | `encrypted_params.isascii()` | `True` | | 文件二进制读取模式 | `open(file_path, 'rb')` | 无`UnicodeDecodeError` | | 请求头自动生成 | `print(encoder.content_type)` | 包含正确boundary | ### 常见错误处理表 | 错误现象 | 原因分析 | 修正方法 | |------------------------------|------------------------------|-----------------------------------| | `ValueError: invalid literal` | 参数包含非ASCII字符 | 增加Base64编码步骤 | | `TypeError: a bytes-like object` | 直接传递加密字节数据 | 使用`.decode('ascii')`转换字符串 | | `UnicodeDecodeError` | 文件未用二进制模式打开 | 检查文件打开模式是否为`rb` | ### 性能优化建议 $$ \text{传输效率} = \frac{\text{原始数据大小}}{\text{Base64编码后大小}} \approx 0.75 $$ 1. 对大文件使用流式上传(分块读取) 2. 对加密参数启用压缩处理: ```python import zlib compressed = zlib.compress(json_str) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值