目录
关于在H5或delphi中使用multipart/form-data上传文件的Rest方法
一、先看官方案例:亚马逊Amazon及微软Azure的CloudAPI云API测试项目
1.1.4、Data.Cloud.CloudAPI.pas // ${YourDelphiInstallPath}\source\data\cloud //:delphi云数据之云计算的公共单元
以上,有官方代码,自己看!下面我用阿里云通讯短信服务API说明如下(代码部分摘自“高勇三层Rest服务器产品”):
3.2、代码的基本步骤(需要你自己按照云服务提供的云API服务的详细说明,一步一步地去接口实现)
3.2.2、签名验证:按API要求获取最终所需的签名字符串Signature
3.2.4、请求服务的Url(Get或Post)、获取响应Response、解析返回结果的JSon或XML数据
3、delphi使用TNetHttp体系时解决Rest应用的代码逻辑:
4、参考网友博文:《深入解析 multipart/form-data》 https://blog.csdn.net/wyn126/article/details/96451357
关于在H5或delphi中使用multipart/form-data上传文件的Rest方法
一、先看官方案例:亚马逊Amazon及微软Azure的CloudAPI云API测试项目
${YourDelphiInstallPath}\Samples\Object Pascal\Database\CloudAPI\CloudAPITest\CloudAPITest.dproj
1、主要涉及的单元:
1.1、CloudRefactorUI.pas // ${YourDelphiInstallPath}\Samples\Object Pascal\Database\CloudAPI\CloudAPITest\ //:云API测试UI主界面单元文件
1.1.2、CloudPopulator.pas // ${YourDelphiInstallPath}\Samples\Object Pascal\Database\CloudAPI\CloudAPITest\ //:云API测试单元文件
1.1.3、Data.Cloud.AmazonAPI.pas // ${YourDelphiInstallPath}\source\data\cloud //:delphi云数据之云计算的亚马逊的API翻译为pascal的单元
1.1.4、Data.Cloud.CloudAPI.pas // ${YourDelphiInstallPath}\source\data\cloud //:delphi云数据之云计算的公共单元
2、申请云服务的步骤:
2.1、首先要到云服务商的平台上申请账号Account
2.1.1、获取账号的User ID
2.1.2、获取账号的AK(账号的Json或XML键值对):Account Key
2.1.2、获取账号的SK(密码的Json或XML键值对):Secret Key
2.2、申请云平台提供的服务及其访问参数的描述
2.2.1、老外好像就叫“Buckets”(tmd的翻译过来叫“水桶”)
2.3、申请服务签名Signature
2.3.1、获取需要的服务的签名Signature
2.4、阅读服务的API访问和代码调用说明
2.4.1、API访问和代码调用说明
3、准备架构和代码的步骤:
3.1、架构与设计
3.1.1、获取账号的User ID
以上,有官方代码,自己看!下面我用阿里云通讯短信服务API说明如下(代码部分摘自“高勇三层Rest服务器产品”):
3.2、代码的基本步骤(需要你自己按照云服务提供的云API服务的详细说明,一步一步地去接口实现)
3.2.1、准备所有API访问公用的资源(变量)
3.2.1.1、baseURL:协议SCHEME(http或https多数云服务要求https) + 特殊保留字Typical scheme '://' + 主机(host域名或IP)
比如阿里云通讯baseURL:https://dysmsapi.aliyuncs.com
3.2.1.2、SortedParams: TArray<string>;:云服务的参数字典键值对数组
比如阿里云短信服务的参数字典键值对数组(以下出斜体注释的部分参数,其余的参数,大部分云服务API参数均大致相同):
Params := TDictionary<string, string>.Create;
Params.Add('AccessKeyId', AccessKeyId); //:AK(见上面2.1.2的说明)
Params.Add('Timestamp', GetTimestamp); //:时间截(不同云服务商不同云服务对其格式有特殊要求)及获取时间截的函数GetTimestamp
Params.Add('Format', 'JSON'); //:请求和响应的数据格式(不同云服务商不同云服务对其数据格式有特殊要求:JSON或XML)
Params.Add('SignatureMethod', 'HMAC-SHA1'); //:签名的加密算法(不同云服务商不同云服务对其算法有特殊要求)
Params.Add('SignatureNonce', THashMD5.GetHashString(TGUID.NewGuid.ToString)); //:每次使用都不一样的一次性加密签名字符串(不同云服务商不同云服务对其有特殊要求:HashMD5常用)
Params.Add('SignatureVersion', '1.0'); //:签名的版本
Params.Add('Action', 'SendSms'); //:服务的具体函数
Params.Add('Version', '2017-05-25'); //:服务的版本
Params.Add('RegionId', 'cn-hangzhou'); //:服务的区域
Params.Add('PhoneNumbers', PhoneNumbers); //:其它该服务特有的必备参数
Params.Add('SignName', SignName); //:申请的服务的签名
Params.Add('TemplateCode', TemplateCode); //:其它该服务特有的必备参数
Params.Add('TemplateParam', TemplateParam); //:其它该服务特有的必备参数
Params.Add('OutId', ''); //:输出的参数或JSON数据
SortedParams := Params.keys.ToArray;
TArray.Sort<string>(SortedParams);
3.2.1.3、构造待签名的请求查询字符串
StringBuilder := TStringBuilder.Create;
//......代码略
SortedQueryString := StringBuilder.ToString.Substring(1);
3.2.1.4、对待签名的请求串进行URL编码,去掉或替换特殊URL编码字符
TNetEncoding.Url.Encode
3.2.2、签名验证:按API要求获取最终所需的签名字符串Signature
签名,云服务器提供你申请,你的客户端代码肯定也就知道,只是需要服务器和客户端双方进行验证,以保证就是申请人(申请机构)在访问自己账号下的云服务
Signature
3.2.3、组装服务的Url
Url := 'https://dysmsapi.aliyuncs.com/?Signature=' + Signature + '&' + SortedQueryString;
3.2.4、请求服务的Url(Get或Post)、获取响应Response、解析返回结果的JSon或XML数据
HTTP.ContentType := 'application/x-www-form-urlencoded'; //: HTTP := TNetHTTPClient.Create(nil);
//:这个HTTP.ContentType便是本文需要讲述的关于html重要head头信息的重要设置赋值
Response := HTTP.Get(Url).ContentAsString(TEncoding.UTF8);
JsonObj := TJSONObject.ParseJSONValue(Response) as TJSONObject;
二、关于multipart/form-data原理
1、什么是multipart/form-data
它是HTML 表单中的编码方式 (Enctype) 之一,有三种类型:
application/x-www-form-urlencoded ==========》对应delphi中的THTTPClient.Post的参数ASource: TMultipartFormData的Mime的类型:TMultipartFormData.Create或TMultipartFormData.AddField或或TMultipartFormData.AddBytes或TMultipartFormData.AddStream的应用程序二进制
如果要发送大量的二进制数据(non-ASCII),application/x-www-form-urlencoded 显然是低效的,因为它需要用 3 个字符来表示一个 non-ASCII 的字符。因此,这种情况下,应该使用 “multipart/form-data” 格式。
multipart/form-data ==========》对应delphi中的THTTPClient.Post的参数ASource: TMultipartFormData的Mime的类型:TMultipartFormData.AddFile的二进制
使用“application / x-www-form-urlencoded”对于发送大量二进制数据或包含非ASCII字符的文本效率低下。“multipart / form-data”应该用于提交包含文件,非ASCII数据和二进制数据的表单。
text-plain(即:默认的application/x-www-urlencoded) ==========》对应delphi中的Get附在 url 链接后面的字符串或Post网页Body部分的内容;或head方法发送头部请求。
默认情况下是 application/x-www-urlencoded,当表单使用 POST 请求时,数据会被以 x-www-urlencoded 方式编码到 Body 中来传送,而如果 GET 请求,则是附在 url 链接后面来发送。GET 请求只支持 ASCII 字符集,因此,如果我们要发送更大字符集的内容,我们应使用 POST 请求。
2、为什么会有multipart/form-data的出现
HTML提交表单数据:
默认情况下是 application/x-www-urlencoded,当表单使用 POST 请求时,数据会被以 x-www-urlencoded 方式编码到 Body 中来传送,而如果 GET 请求,则是附在 url 链接后面来发送。GET 请求只支持 ASCII 字符集,因此,如果我们要发送更大字符集的内容,我们应使用 POST 请求。
如果要发送大量的二进制数据(non-ASCII),application/x-www-form-urlencoded 显然是低效的,因为它需要用 3 个字符来表示一个 non-ASCII 的字符。因此,这种情况下,应该使用 “multipart/form-data” 格式。
使用“application / x-www-form-urlencoded”对于发送大量二进制数据或包含非ASCII字符的文本效率低下。“multipart / form-data”应该用于提交包含文件,非ASCII数据和二进制数据的表单。
3、delphi使用TNetHttp体系时解决Rest应用的代码逻辑:
delphi的Rest解决方案:《delphi Restful:客户端实现的四种方式及其比较》:https://blog.csdn.net/pulledup/article/details/104132753
System.Net.HttpClientComponent.pas ==========》 HTTP := TNetHTTPClient.Create(nil); ==========》
关于表单的多个数据对象TMultipartFormData的提交:
1、Post表单的多个数据对象
function Post(const AURL: string; const ASource: TMultipartFormData; const AResponseContent: TStream = nil;
const AHeaders: TNetHeaders = nil): IHTTPResponse; overload;
2、Put表单的多个数据对象
function Put(const AURL: string; const ASource: TMultipartFormData; const AResponseContent: TStream = nil;
const AHeaders: TNetHeaders = nil): IHTTPResponse; overload; ==========》 IHTTPResponse : System.Net.HttpClient.pas
System.Net.HttpClient.pas ==========》 FHttpClient := THTTPClient.Create; FHttpClient.OnReceiveData := DoOnReceiveData; Result := THTTPClient(TURLSchemes.GetURLClientInstance('HTTP')); ==========》
System.Net.URLClient.pas ==========》 FSchemeClients.TryGetValue(AScheme.ToUpper, LClientClass); if LClientClass <> nil then Result := LClientClass.CreateInstance;TURLClient.CreateInstance: TURLClient; TURLClient.SetCustomHeaderValue(const Name, Value: string);
System.Net.Mime.pas ==========》
(
TMultipartFormData = class (TObject) //:详见类的Public公开属性和方法
TMimeTypes = class (TObject) //:详见类的Public公开属性和方法 ===========》HTTP.ContentType := 'MimeType的类型值';
TAcceptValueListBase<T: TAcceptValueItem, constructor> = class (TObject) //:详见类的Public公开属性和方法
THeaderValueList = class (TObject) //:详见类的Public公开属性和方法
)
System.NetConsts.pas ==========》(常量、错误提示)
//: uses System.NetConsts;
const
DefaultUserAgent = 'Embarcadero URI Client/1.0'; // Do not translate
// Common Header Names
sUserAgent = 'User-Agent'; // Do not translate
sAccept = 'Accept'; // Do not translate
sAcceptCharset = 'Accept-Charset'; // Do not translate
sAcceptEncoding = 'Accept-Encoding'; // Do not translate
sAcceptLanguage = 'Accept-Language'; // Do not translate
sAcceptRanges = 'Accept-Ranges'; // Do not translate
sContentEncoding = 'Content-Encoding'; // Do not translate
sContentLanguage = 'Content-Language'; // Do not translate
sContentLength = 'Content-Length'; // Do not translate
sContentType = 'Content-Type'; // Do not translate
sLastModified = 'Last-Modified'; // Do not translate
sContentDisposition = 'Content-Disposition'; // Do not translate
sLocation = 'Location'; // Do not translate
sSetCookie = 'Set-Cookie'; // Do not translate
sCookie = 'Cookie'; // Do not translate
sRange = 'Range'; // Do not translate
sXMethodOverride = 'x-method-override'; // Do not translate
sWWWAuthenticate = 'WWW-Authenticate'; // Do not translate
sProxyAuthenticate = 'Proxy-Authenticate'; // Do not translate
sAuthorization = 'Authorization'; // Do not translate
sProxyAuthorization = 'Proxy-Authorization'; // Do not translat
4、参考网友博文:《深入解析 multipart/form-data》 https://blog.csdn.net/wyn126/article/details/96451357
本博客相关:
1、《delphi Restful:客户端实现的四种方式及其比较》
2、《RAD Studio 10.4.1的TEdgeBrowser与javascript交互-基于Chromium的Edge浏览器控件用法之二》
3、《Delphi Restful之客户端javascript与中间件服务器交互》