使用Indy TIdHttp.Put调用MS Graph API的Content-Range头异常问题
问题原因和解决方法
核心问题原因
- 首先
TIdHTTP的Ranges属性是用于GET请求时向服务器请求部分内容的,会生成Range请求头,不会在PUT请求中自动生成Content-Range头,所以用这个属性必然会报缺少Content-Range的错误。 - 直接往
CustomHeaders里加Content-Range报错的原因有两个:- 你的流处理逻辑错误:你把文件内容读取后用
{}包裹,实际传输的内容长度和你在Content-Range、Content-Length里声明的长度完全不匹配,Graph API校验时发现范围和实际传输字节数不一致,就会报头无效。 - Indy会自动处理部分标准HTTP头,你手动加在
CustomHeaders里的Content-Range可能会被Indy内部逻辑覆盖或者修改,导致最终发出的头格式不符合要求。
- 你的流处理逻辑错误:你把文件内容读取后用
适配修改方案
Indy的PUT请求是符合HTTP标准的,只需要调整使用方式即可适配该场景,修改如下:
- 修正流处理逻辑:上传会话的PUT请求需要传输原始的二进制文件内容,不需要额外加JSON包装,直接用
TFileStream读取文件即可。 - 不要使用
Ranges属性,也不要手动往CustomHeaders里加Content-Range,使用Indy内置的请求参数配置即可:
sUploadSession := jsnUSession.Get('uploadUrl').JsonValue.Value; Form1.htp2.ProtocolVersion := pv1_1; // 必须用HTTP 1.1协议才支持请求端发送Content-Range头 Form1.htp2.Request.ContentType := 'application/octet-stream'; // 配置Content-Range参数 Form1.htp2.Request.ContentRangeStart := 0; Form1.htp2.Request.ContentRangeEnd := iSize - 1; Form1.htp2.Request.ContentRangeInstanceLength := iSize; Form1.htp2.Request.ContentLength := iSize; fs := TFileStream.Create(sFile, fmOpenRead or fmShareDenyWrite); try try Form1.htp2.Put(sUploadSession, fs); except on E: EIdHTTPProtocolException do Form1.RichEdit1.Lines.Add(E.Message + #13#10 + E.ErrorMessage); end; finally fs.Free; end;
- 如果是分片上传的场景,只需要对应修改
ContentRangeStart、ContentRangeEnd的值为当前分片的字节范围,同时调整ContentLength为当前分片的大小即可。
内容的提问来源于stack exchange,提问作者Moore
相关产品推荐
相关产品推荐

