You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python上传大文件至第三方ResApi服务器遇413错误,添加Expect:100-continue后触发连接中止问题求助

解决Python上传大文件时Expect:100-continue导致的连接中止问题

根据你的描述,Perl和C#代码通过添加Expect:100-continue头部就能成功上传大文件,但Python实现却出现连接中止错误,这大概率是因为requests库与自定义SSL Adapter的交互,以及MultipartEncoder的流式传输方式,干扰了100-continue的正常握手流程。以下是几个针对性的解决方案:

方案1:修改SSLAdapter,显式启用100-continue支持

urllib3的PoolManager默认启用expect_100_continue,但自定义SSLAdapter时可能没有传递这个参数,导致服务器返回100-continue后客户端无法正确响应。修改你的SSLAdapter类:

class SSLAdapter(HTTPAdapter):
    '''An HTTPS Transport Adapter that uses an arbitrary SSL version.'''
    def __init__(self, ssl_version=None, **kwargs):
        self.ssl_version = ssl_version
        super(SSLAdapter, self).__init__(**kwargs)

    def init_poolmanager(self, connections, maxsize, block=False):
        self.poolmanager = PoolManager(
            num_pools=connections,
            maxsize=maxsize,
            block=block,
            ssl_version=self.ssl_version,
            expect_100_continue=True  # 显式启用100-continue支持
        )

然后确保在请求中正确添加Expect头部(添加到Session层面更可靠):

s = Session()
s.headers.update({'Expect': '100-continue', 'Accept': 'application/json'})
s.mount('https://', SSLAdapter(ssl.PROTOCOL_TLSv1_2))

方案2:改用requests原生的files参数,避免手动构造MultipartEncoder

你当前使用MultipartEncoder实现流式上传,但requests原生的files参数会自动处理大文件的100-continue逻辑,兼容性更好。重构sendFile方法:

def sendFile(self, my1GBFile):
    self.base_url = 'https://myserver.com/fileBoxServer/api/ssl/files/upload';
    s = Session()
    s.headers.update({'Expect': '100-continue', 'Accept': 'application/json'})
    s.mount('https://', SSLAdapter(ssl.PROTOCOL_TLSv1_2))

    # 使用requests原生files参数,自动处理multipart和100-continue
    with open(my1GBFile, 'rb') as file_obj:
        file_data = {
            'file': (os.path.basename(my1GBFile), file_obj, 'text/plain')
        }
        print('Sending filebox...')
        r = s.post(
            self.base_url,
            files=file_data,
            verify=self.ca_file,
            cert=(self.cert_file, self.key_file),
            timeout=54000
        )

    if r.ok:
        cookies = dict(r.cookies)
        print("cookies: ", cookies)
    else:
        print("Error: HTTP %i - %s, Message %s" % (r.status_code, r.reason, r.text))

这种方式会让requests自动处理请求体的分块和100-continue握手,避免流式传输带来的兼容性问题。

方案3:升级依赖库到最新兼容版本

旧版本的requests或urllib3可能存在Expect:100-continue的处理bug,尤其是Python3.8.5搭配的旧版本依赖。执行以下命令升级:

pip install --upgrade requests requests-toolbelt urllib3

升级后再测试原代码,很多时候这类兼容性问题会被新版本修复。

方案4:禁用请求预处理的头部覆盖

如果手动添加的Expect头部被requests自动覆盖,可以尝试在构造Request时禁用自动处理:

req = Request('POST', self.base_url, data=multipart_data, headers={
    'Content-Type': multipart_data.content_type,
    'Accept': 'application/json',
    'Expect': '100-continue'
})
prepped = req.prepare()
# 确保Expect头部没有被移除或修改
prepped.headers['Expect'] = '100-continue'

然后再发送预处理后的请求。

为什么Perl/C#可以正常工作?

Perl的LWP和C#的HttpClient对Expect:100-continue的处理更直接,且不会像requests那样在自定义Adapter时丢失相关配置,同时它们的multipart请求实现与100-continue握手的兼容性更好。

内容的提问来源于stack exchange,提问作者Josue Medrano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 11:52:38