使用可恢复上传至GCS存储桶时遇'Response headers must contain header'错误
我尝试通过可恢复上传功能将视频上传至Google Cloud Storage存储桶,但始终遇到相同错误:(u'Response headers must contain header', u'location')。错误出现在upload.initiate()方法执行时。以下是我的代码:
client = _get_storage_client() bucket = client.bucket(BUCKET_NAME, PROJECT_ID) blob = bucket.blob(filename) if 'video' in content_type: url = blob.create_resumable_upload_session(content_type=content_type, client=client) stream = io.BytesIO(stream_file.file.read()) upload = ResumableUpload( upload_url=url, chunk_size=chunk_size ) transport = AuthorizedSession(credentials=client._credentials) # Start using the Resumable Upload response = upload.initiate( transport=transport, content_type=content_type, stream=stream, metadata={'name': blob.name} ) while upload.finished is False: upload.transmit_next_chunk(transport)
我帮你分析下这个问题——你遇到的location头部缺失错误,核心原因是手动使用ResumableUpload时,重复传递了不必要的元数据,和create_resumable_upload_session返回的URL配置产生了冲突。
具体来说,blob.create_resumable_upload_session已经帮你完成了会话初始化的核心工作,返回的上传URL里已经包含了对象名称(也就是你设置的blob.name)等必要元数据。你在upload.initiate里再次传递metadata={'name': blob.name},反而会让请求出现异常,导致GCS返回的响应缺少了关键的location头部。
给你两个实用的解决思路:
思路一:修正手动ResumableUpload的使用方式
调整代码,去掉initiate方法里的metadata参数,同时注意create_resumable_upload_session不需要额外传递client参数(blob已经关联了客户端):
client = _get_storage_client() bucket = client.bucket(BUCKET_NAME, PROJECT_ID) blob = bucket.blob(filename) if 'video' in content_type: # 创建可恢复上传会话,无需额外传递client参数 upload_url = blob.create_resumable_upload_session(content_type=content_type) stream = io.BytesIO(stream_file.file.read()) upload = ResumableUpload(upload_url=upload_url, chunk_size=chunk_size) transport = AuthorizedSession(credentials=client._credentials) # 初始化上传,去掉重复的metadata参数 response = upload.initiate( transport=transport, content_type=content_type, stream=stream ) while not upload.finished: upload.transmit_next_chunk(transport)
思路二:使用客户端内置的可恢复上传方法
其实Google Cloud Storage的Python客户端已经封装了更易用的可恢复上传逻辑,完全不需要手动操作ResumableUpload类,代码会简洁很多,也更可靠:
client = _get_storage_client() bucket = client.bucket(BUCKET_NAME, PROJECT_ID) blob = bucket.blob(filename) if 'video' in content_type: stream = io.BytesIO(stream_file.file.read()) # 直接启用resumable参数即可自动处理可恢复上传 blob.upload_from_file( stream, content_type=content_type, resumable=True, chunk_size=chunk_size )
这个内置方法会自动处理会话初始化、分块上传、断点续传等所有逻辑,能帮你避开手动实现时容易踩的坑。
内容的提问来源于stack exchange,提问作者Dannick Montanede

