如何向Azure上传JSON文件?调用PUT接口返回201却未成功上传
问题分析与修复方案
1. 硬编码x-ms-date导致签名验证异常
Azure存储服务要求x-ms-date必须为当前UTC时间(且需处于SAS令牌的有效期范围内)。你代码中硬编码为2023-02-28,尽管服务器返回201状态码,但时间不匹配可能导致写入操作被静默拒绝。
修复:动态生成符合格式要求的UTC时间字符串:
uses System.DateUtils, System.SysUtils; function GetAzureDateString: string; begin // 生成RFC1123格式的UTC时间:Sun, 06 Nov 1994 08:49:37 GMT Result := FormatDateTime('ddd, dd mmm yyyy hh:nn:ss "GMT"', TTimeZone.Local.ToUniversalTime(Now)); // 确保月份缩写为英文标准格式 Result := StringReplace(Result, 'Jan', 'Jan', [rfIgnoreCase]); Result := StringReplace(Result, 'Feb', 'Feb', [rfIgnoreCase]); Result := StringReplace(Result, 'Mar', 'Mar', [rfIgnoreCase]); Result := StringReplace(Result, 'Apr', 'Apr', [rfIgnoreCase]); Result := StringReplace(Result, 'May', 'May', [rfIgnoreCase]); Result := StringReplace(Result, 'Jun', 'Jun', [rfIgnoreCase]); Result := StringReplace(Result, 'Jul', 'Jul', [rfIgnoreCase]); Result := StringReplace(Result, 'Aug', 'Aug', [rfIgnoreCase]); Result := StringReplace(Result, 'Sep', 'Sep', [rfIgnoreCase]); Result := StringReplace(Result, 'Oct', 'Oct', [rfIgnoreCase]); Result := StringReplace(Result, 'Nov', 'Nov', [rfIgnoreCase]); Result := StringReplace(Result, 'Dec', 'Dec', [rfIgnoreCase]); end;
替换硬编码的x-ms-date参数:
RESTRequest.Params.AddItem('x-ms-date', GetAzureDateString, TRESTRequestParameterKind.pkHTTPHEADER, [poDoNotEncode]);
2. AnsiString转换破坏JSON编码
如果JSON文件包含非ASCII字符(如中文、特殊符号),AnsiString会丢失UTF-8编码信息,导致上传内容无效,被存储服务静默丢弃。
修复:直接使用文件流上传(避免字符串转换,更可靠):
// 在SendFileToCloud函数中替换请求体部分 FileContent := ReadBytesAsStream(AFileName); try RESTRequest.AddBody(FileContent, ctAPPLICATION_JSON); RESTRequest.Execute; finally FileContent.Free; end;
3. 补充REST请求配置
TRESTRequest默认设置可能导致请求未正确送达,添加以下配置确保请求严格执行:
// 禁用自动重定向,避免请求被意外转发 RESTRequest.Options := RESTRequest.Options + [roNoAutoRedirect]; // 显式设置Content-Type,确保服务器识别请求格式 RESTClient.ContentType := 'application/json';
4. 验证SAS令牌有效性
确认SAS令牌的:
sp权限包含w(写权限)st(开始时间)和se(过期时间)覆盖当前时间sig签名无拼接错误
修改后的完整代码示例
uses System.DateUtils, System.SysUtils, System.Classes; function ReadBytesAsStream(const AFileName: string): TStream; begin Result := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite); end; function GetAzureDateString: string; begin Result := FormatDateTime('ddd, dd mmm yyyy hh:nn:ss "GMT"', TTimeZone.Local.ToUniversalTime(Now)); Result := StringReplace(Result, 'Jan', 'Jan', [rfIgnoreCase]); Result := StringReplace(Result, 'Feb', 'Feb', [rfIgnoreCase]); Result := StringReplace(Result, 'Mar', 'Mar', [rfIgnoreCase]); Result := StringReplace(Result, 'Apr', 'Apr', [rfIgnoreCase]); Result := StringReplace(Result, 'May', 'May', [rfIgnoreCase]); Result := StringReplace(Result, 'Jun', 'Jun', [rfIgnoreCase]); Result := StringReplace(Result, 'Jul', 'Jul', [rfIgnoreCase]); Result := StringReplace(Result, 'Aug', 'Aug', [rfIgnoreCase]); Result := StringReplace(Result, 'Sep', 'Sep', [rfIgnoreCase]); Result := StringReplace(Result, 'Oct', 'Oct', [rfIgnoreCase]); Result := StringReplace(Result, 'Nov', 'Nov', [rfIgnoreCase]); Result := StringReplace(Result, 'Dec', 'Dec', [rfIgnoreCase]); end; function SendFileToCloud(AFilename: String; ShowErrors: Boolean): Boolean; CONST Container= 'MyContainer/'; BaseURL = 'https://xyz.blob.core.windows.net/'+ Container; JWT = 'sp=rcwl&st=2022-10-04T00:00:26Z&' +'se=2025-12-31T21:00:26Z&spr=https&' +'sv=2021-06-08&' +'sr=c&sig=blablabla'; VAR FinalURL: String; FileName: String; FileContent: TStream; RESTClient: TRESTClient; RESTRequest: TRESTRequest; RESTResponse: TRESTResponse; begin Result:= TRUE; RESTClient:= NIL; RESTRequest:= NIL; RESTResponse:= NIL; // Create URL. FileName := ExtractFileName(aFilename); FinalURL := BaseURL + FileName + '?' + JWT; TRY // create REST objects RESTClient := TRESTClient.Create(FinalURL); RESTRequest := TRESTRequest.Create(RESTClient); RESTResponse := TRESTResponse.Create(RESTClient); RESTRequest.Client := RESTClient; RESTRequest.Response := RESTResponse; RESTRequest.Method := TRestRequestMethod.rmPUT; RESTRequest.Options := RESTRequest.Options + [roNoAutoRedirect]; RESTClient.ContentType := 'application/json'; // HEADER RESTRequest.Params.AddItem('x-ms-blob-type', 'BlockBlob', TRESTRequestParameterKind.pkHTTPHEADER, [poDoNotEncode]); RESTRequest.Params.AddItem('x-ms-version', '2021-06-08', TRESTRequestParameterKind.pkHTTPHEADER, [poDoNotEncode]); RESTRequest.Params.AddItem('x-ms-date', GetAzureDateString, TRESTRequestParameterKind.pkHTTPHEADER, [poDoNotEncode]); // FILE BODY FileContent := ReadBytesAsStream(AFileName); try RESTRequest.AddBody(FileContent, ctAPPLICATION_JSON); RESTRequest.Execute; // 可选:查看响应内容排查隐藏错误 if ShowErrors then ShowMessage(RESTResponse.Content); finally FileContent.Free; end; FINALLY RESTResponse.Free; RESTRequest.Free; RESTClient.Free; END; end;
内容的提问来源于stack exchange,提问作者Error - CPU Not Foud
相关产品推荐
相关产品推荐

