内容简介:使用 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#×tamp=#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#×tamp=#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;
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 在 Visual Studio 中重新将高级保存功能放出来,便于强制指定文件编码格式
- c# – “SMTP主机未指定” – 但是是否指定?
- 运维安全 | 如何限制指定账户不能SSH只能SFTP在指定目录
- Zabbix监控指定端口
- Android指定专用APN
- iOS 指定初始化方法
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Spring in Action
Craig Walls / Manning Publications / 2011-6-29 / USD 49.99
Spring in Action, Third Edition has been completely revised to reflect the latest features, tools, practices Spring offers to java developers. It begins by introducing the core concepts of Spring and......一起来看看 《Spring in Action》 这本书的介绍吧!