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

如何向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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 11:28:28