使用 THttpClient Post时发送指定编码的文本内容

栏目: 编程语言 · 发布时间: 6年前

内容简介:使用 THttpClient Post时发送指定编码的文本内容

THttpClient 是 Delphi/C++ Builder 新引入的一个 HTTP/HTTPS 协议客户端的封装,相当好用。我现在已经基本上不使用 libcurl 了,它已经能满足我绝大多数情况下的 HTTP 操作请求。

不过,最近遇到了一点小问题,我们先看 Post 函数的声明:

Delphi/Pascal

/// <summary>Post a raw file without multipart info</summary>
    function Post(const AURL: string; const ASourceFile: string; const AResponseContent: TStream = nil; const AHeaders: TNetHeaders = nil): IHTTPResponse; overload;
    /// <summary>Post TStrings values adding multipart info</summary>
    function Post(const AURL: string; const ASource: TStrings; const AResponseContent: TStream = nil;
      const AEncoding: TEncoding = nil; const AHeaders: TNetHeaders = nil): IHTTPResponse; overload;
    /// <summary>Post a stream without multipart info</summary>
    function Post(const AURL: string; const ASource: TStream; const AResponseContent: TStream = nil;
      const AHeaders: TNetHeaders = nil): IHTTPResponse; overload;
    /// <summary>Post a multipart form data object</summary>
    function Post(const AURL: string; const ASource: TMultipartFormData; const AResponseContent: TStream = nil;
      const AHeaders: TNetHeaders = nil): IHTTPResponse; overload;
 /// <summary>Post a raw file without multipart info</summary>
    function Post(const AURL: string; const ASourceFile: string; const AResponseContent: TStream = nil; const AHeaders: TNetHeaders = nil): IHTTPResponse; overload;
    /// <summary>Post TStrings values adding multipart info</summary>
    function Post(const AURL: string; const ASource: TStrings; const AResponseContent: TStream = nil;
      const AEncoding: TEncoding = nil; const AHeaders: TNetHeaders = nil): IHTTPResponse; overload;
    /// <summary>Post a stream without multipart info</summary>
    function Post(const AURL: string; const ASource: TStream; const AResponseContent: TStream = nil;
      const AHeaders: TNetHeaders = nil): IHTTPResponse; overload;
    /// <summary>Post a multipart form data object</summary>
    function Post(const AURL: string; const ASource: TMultipartFormData; const AResponseContent: TStream = nil;
      const AHeaders: TNetHeaders = nil): IHTTPResponse; overload;

这是 THttpClient 的 Post 的几个重载,如果我要直接提交一个 JSON 或 XML 字符串到服务器端,上面的第 1 种重载要求先保存到文件再提交,第 2 种重载要求的是一个 TStrings 对象,看起来很有戏,第三个重载是投寄一个流进去,看起来也有戏,第四种重载明显就是我们需要的了。

好吧,然后我们进入第 2 种重载的源码,发现了什么?

Delphi/Pascal

LParams := '';
  for I := 0 to ASource.Count - 1 do
  begin
    Pos := ASource[I].IndexOf('=');
    if Pos > 0 then
      LParams := LParams + ASource[I].Substring(0, Pos) + '=' + TURI.URLEncode(ASource[I].Substring(Pos + 1), True) + '&';
  end;
  LParams := LParams.Substring(0, LParams.Length - 1); // Remove last &
LParams := '';
  for I := 0 to ASource.Count - 1 do
  begin
    Pos := ASource[I].IndexOf('=');
    if Pos > 0 then
      LParams := LParams + ASource[I].Substring(0, Pos) + '=' + TURI.URLEncode(ASource[I].Substring(Pos + 1), True) + '&';
  end;
  LParams := LParams.Substring(0, LParams.Length - 1); // Remove last &

也就是说,它传递的是实际上是 Name -Value 值对,没配对的直接忽略掉了。显然也不符合我们的要求,可以被 Pass 掉了。剩下的唯一选择就是传递一个流进去。

好了,QJSON 和 QXML 都提供了保存到流里的支持,所以创建一个临时的内存流,保存下来后做为参数传递进去,用完释放就 OK 了。如果嫌不够直观,还可以用 QMacros 来用模板替换的方式来替换,效率一样杠杠的。下面是一个简单的例子(用 THttpClient 用轻码云发送模板短信):

Delphi/Pascal

var
  AResponse: IHttpResponse;
  AUrl: String;
  AMacros: TQMacroManager;
  AReply, AItem: TQJson;
  ATimeStamp: String;
  AStream: TStringStream;
const
  AVerifyUrl
    : String =
    '#protocol#://api.qingmayun.com/#SoftVersion#/accounts/#accountSid#/SMS/templateSMS?'
    + 'sig=#sig#&timestamp=#timestamp#';
  APostContent: String = '{'#13#10 + '"templateSMS": {'#13#10 +
    '    "appId": "#appId#",'#13#10 + '    "templateId": "#templateId#",'#13#10
    + '    "to": "#to#",'#13#10 + '    "param": "#param#"'#13#10 +
    ' }'#13#10 + '}';
  function CalcSign: String;
  var
    S: String;
    ADigest: TQMD5Digest;
  begin
    S := AccountId + AuthToken + ATimeStamp;
    ADigest := MD5Hash(S);
    Result := BinToHex(@ADigest, SizeOf(ADigest), true);
  end;

begin
  Result := False;
  AMacros := TQMacroManager.Create;
  AStream := TStringStream.Create('', TEncoding.UTF8, False);
  try
    ATimeStamp := FormatDateTime('yyyymmddhhnnss', Now);
    AMacros.Push('protocol', 'https');
    AMacros.Push('SoftVersion', '20141029');
    AMacros.Push('accountSid', AccountId);
    AMacros.Push('appId', AppId);
    AMacros.Push('templateId', TemplateId);
    AMacros.Push('to', APhoneNum);
    AMacros.Push('param', ACode + ',30');
    AMacros.Push('sig', CalcSign);
    AMacros.Push('timestamp', ATimeStamp);
    AUrl := AMacros.Replace(AVerifyUrl, '#', '#');
    FHttpClient.Accept := 'application/json';
    FHttpClient.ContentType := 'application/json;charset=utf-8';
    AStream.WriteString(AMacros.Replace(APostContent, '#', '#',
      MRF_IN_DBL_QUOTER));
    AStream.Position := 0;
    AResponse := FHttpClient.Post(AUrl, AStream);
    if Assigned(AResponse) then
    begin
      if AResponse.StatusCode = 200 then
      begin
        AReply := TQJson.Create;
        try
          if AReply.TryParse(AResponse.ContentAsString()) then
          begin
            FLastError := AReply.ValueByPath('result.respCode', '');
            if FLastError = '00000' then
              Result := true;
          end;
        finally
          FreeAndNil(AReply);
        end;
      end
      else
        FLastError := IntToStr(AResponse.StatusCode);
    end
    else
      FLastError := '-1';
  finally
    FreeAndNil(AMacros);
  end;
var
  AResponse: IHttpResponse;
  AUrl: String;
  AMacros: TQMacroManager;
  AReply, AItem: TQJson;
  ATimeStamp: String;
  AStream: TStringStream;
const
  AVerifyUrl
    : String =
    '#protocol#://api.qingmayun.com/#SoftVersion#/accounts/#accountSid#/SMS/templateSMS?'
    + 'sig=#sig#&timestamp=#timestamp#';
  APostContent: String = '{'#13#10 + '"templateSMS": {'#13#10 +
    '    "appId": "#appId#",'#13#10 + '    "templateId": "#templateId#",'#13#10
    + '    "to": "#to#",'#13#10 + '    "param": "#param#"'#13#10 +
    ' }'#13#10 + '}';
  function CalcSign: String;
  var
    S: String;
    ADigest: TQMD5Digest;
  begin
    S := AccountId + AuthToken + ATimeStamp;
    ADigest := MD5Hash(S);
    Result := BinToHex(@ADigest, SizeOf(ADigest), true);
  end;
 
begin
  Result := False;
  AMacros := TQMacroManager.Create;
  AStream := TStringStream.Create('', TEncoding.UTF8, False);
  try
    ATimeStamp := FormatDateTime('yyyymmddhhnnss', Now);
    AMacros.Push('protocol', 'https');
    AMacros.Push('SoftVersion', '20141029');
    AMacros.Push('accountSid', AccountId);
    AMacros.Push('appId', AppId);
    AMacros.Push('templateId', TemplateId);
    AMacros.Push('to', APhoneNum);
    AMacros.Push('param', ACode + ',30');
    AMacros.Push('sig', CalcSign);
    AMacros.Push('timestamp', ATimeStamp);
    AUrl := AMacros.Replace(AVerifyUrl, '#', '#');
    FHttpClient.Accept := 'application/json';
    FHttpClient.ContentType := 'application/json;charset=utf-8';
    AStream.WriteString(AMacros.Replace(APostContent, '#', '#',
      MRF_IN_DBL_QUOTER));
    AStream.Position := 0;
    AResponse := FHttpClient.Post(AUrl, AStream);
    if Assigned(AResponse) then
    begin
      if AResponse.StatusCode = 200 then
      begin
        AReply := TQJson.Create;
        try
          if AReply.TryParse(AResponse.ContentAsString()) then
          begin
            FLastError := AReply.ValueByPath('result.respCode', '');
            if FLastError = '00000' then
              Result := true;
          end;
        finally
          FreeAndNil(AReply);
        end;
      end
      else
        FLastError := IntToStr(AResponse.StatusCode);
    end
    else
      FLastError := '-1';
  finally
    FreeAndNil(AMacros);
  end;

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

深入理解并行编程

深入理解并行编程

[美] Paul E.Mckenney(保罗·E·麦肯尼) / 谢宝友 鲁阳 / 电子工业出版社 / 2017-7-1 / 129

《深入理解并行编程》首先以霍金提出的两个理论物理限制为引子,解释了多核并行计算兴起的原因,并从硬件的角度阐述并行编程的难题。接着,《深入理解并行编程》以常见的计数器为例,探讨其不同的实现方法及适用场景。在这些实现方法中,除了介绍常见的锁以外,《深入理解并行编程》还重点介绍了RCU的使用及其原理,以及实现RCU的基础:内存屏障。最后,《深入理解并行编程》还介绍了并行软件的验证,以及并行实时计算等内容......一起来看看 《深入理解并行编程》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具