使用XMLHttpRequest获取ETag时得到字符串浮点数而非预期Base64值
问题原因及解决方案
原因
CloudFlare R2在处理采用**分块传输(Transfer-Encoding: chunked)**的PUT请求时,会返回一个临时的ETag(即你看到的浮点数格式字符串)。这个临时值是上传过程中的中间标识,而非对象最终持久化后的真实ETag(也就是开发者工具里显示的Base64字符串)。
之所以出现不一致,是因为分块上传时R2会在接收完全部数据前就返回响应头,XMLHttpRequest捕获到的是这个早期的临时ETag;而开发者工具可能展示的是对象上传完成后,通过后续隐式请求(或刷新后)获取到的真实元数据。
解决方案
有两种方式可以获取到正确的ETag:
1. 上传完成后发送HEAD请求
PUT请求成功后,对同一个对象URL发送HEAD请求,直接获取对象的真实元数据(包括正确的Base64格式ETag):
// 封装HEAD请求获取真实ETag function fetchRealETag(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('HEAD', url); xhr.onreadystatechange = () => { if (xhr.readyState === 4) { if (xhr.status === 200) { resolve(xhr.getResponseHeader('ETag')); } else { reject(new Error(`HEAD 请求失败,状态码:${xhr.status}`)); } } }; xhr.send(); }); } // 在PUT请求成功后调用 // 假设原PUT请求的readyState===4且status===200时执行: fetchRealETag(url).then(realETag => { console.log('真实ETag:', realETag); }).catch(err => { console.error(err); });
2. 显式设置Content-Length请求头
如果上传内容的大小已知,在PUT请求中添加Content-Length请求头,R2会等待接收完全部数据后再返回最终的真实ETag,避免临时值问题:
const xhr = new XMLHttpRequest(); xhr.open('PUT', url); // 假设chunk是Blob、File或ArrayBuffer类型 const contentLength = chunk instanceof Blob ? chunk.size : chunk.byteLength; xhr.setRequestHeader('Content-Length', contentLength); xhr.addEventListener('readystatechange', () => { if (xhr.readyState === 4 && xhr.status === 200) { const eTag = xhr.getResponseHeader('ETag'); console.log({ eTag, headers: xhr.getAllResponseHeaders() }); } }); xhr.send(chunk);
内容的提问来源于stack exchange,提问作者knpwrs
相关产品推荐
相关产品推荐

