内容简介:使用 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 指定初始化方法
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JAVA核心技术(卷1)
Cay S. Horstmann、Gary Cornell / 杜永萍、邝劲筠、叶乃文 / 机械工业出版社 / 2008-6 / 98.00元
《JAVA核心技术(卷1):基础知识(原书第8版)》是《Java核心技术》的最新版,《Java核心技术》出版以来一直畅销不衰,深受读者青睐,每个新版本都尽可能快地跟上Java开发工具箱发展的步伐,而且每一版都重新改写了的部分内容,以便适应Java的最新特性。本版也不例外,它反遇了Java SE6的新特性。全书共14章,包括Java基本的程序结构、对象与类、继承、接口与内部类、图形程序设计、事件处理......一起来看看 《JAVA核心技术(卷1)》 这本书的介绍吧!