相关文章推荐
月球上的柑橘  ·  机器学习 Christopher ...·  3 月前    · 
飘逸的野马  ·  关于及时升级nginx ...·  4 月前    · 
骑白马的茄子  ·  Android VideoView or ...·  6 月前    · 

关于在H5或delphi中使用multipart/form-data上传文件的Rest方法

一、先看官方案例:亚马逊Amazon及微软Azure的CloudAPI云API测试项目

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.2、申请云平台提供的服务及其访问参数的描述

2.3、申请服务签名Signature

2.4、阅读服务的API访问和代码调用说明

3、准备架构和代码的步骤:

3.1、架构与设计

3.1.1、获取账号的User ID

以上,有官方代码,自己看!下面我用阿里云通讯短信服务API说明如下(代码部分摘自“高勇三层Rest服务器产品”):

3.2、代码的基本步骤(需要你自己按照云服务提供的云API服务的详细说明,一步一步地去接口实现)

3.2.1、准备所有API访问公用的资源(变量)

3.2.2、签名验证:按API要求获取最终所需的签名字符串Signature

3.2.3、组装服务的Url

3.2.4、请求服务的Url(Get或Post)、获取响应Response、解析返回结果的JSon或XML数据

二、关于multipart/form-data原理

1、什么是multipart/form-data

2、为什么会有multipart/form-data的出现

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.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与中间件服务器交互》

喜欢的话,就在下面点个赞、收藏就好了,方便看下次的分享:

关于在H5或delphi中使用multipart/form-data上传文件https://blog.csdn.net/wyn126/article/details/96451357
我们都知道要让form能提交 文件 ,需要在form上指定enctype= multipart / form-data 的attribute,这样才能上 文件 ,关于enctype的文章很多,就不再做解释。 问题是因为 使用 了MVC的Html.BeginForm()来输出表单代码,默认是没有加入enctype的, 代码如下: @using (Html.BeginForm()) { } 在PartialView 有一个<input type=”file” />用来上 文件 ,又不想为了这个PartialView去修改父页面的Html.BeginForm(),我的做法是在PartialView 用脚本来为for
最近,实现一个网站的登录查询。遇到 multipart / form-data 数据提交。 POST /admin/api/common/syslogin HTTP/1.1 Host: xxx.xx.xx.xxx Connection: keep-alive Accept: / X-Requested-With: XMLHttpRequest User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like
开始前,先看下要实现的微信接口,上 多媒体 文件 ,这个接口是用Form表单形式上 文件 。对我来说,对http的Form表单一知半解,还好,查到这个资料,如果你也和我一样,必须看看这篇文章。 在xalion窑主的指导下,我 使用 了indy自带的TId MultiPart FormDataStre am类,来提交上 文件 。 如果 使用 indy的idhttp,则调用这个 方法 ,即可以提交For...
import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletR
pb multipart / form-data 是一种用于在HTTP请求 文件 和数据的 方法 。它在请求主体 使用 分隔线分隔数据,并且每个部分都包含一个标头和一个数据块。其 ,标头指定了数据块的类型、名称和其他信息,数据块则包含实际上 文件 内容。 在 使用 pb multipart / form-data 文件 时,首先需要构建一个HTTP请求,并且指定Content-Type头部为 multipart / form-data 。然后,将需要上 文件 读取为二进制数据,并将其封装成数据块的形式,同时设置好相应的标头信息。如果还有其他需要上 的表单数据,也需要封装成相应的数据块形式,并设置好标头信息。 最后,将所有数据块按照分隔线拼接起来,并将拼接后的数据作为请求主体发送到服务器。服务器收到请求后,解析请求主体 的数据,并根据标头信息进行相应的处理,从而完成 文件 的上 和其他表单数据的提交。 需要注意的是,在 使用 pb multipart / form-data 文件 时,因为数据需要封装成数据块并进行分隔线拼接,所以相比普通的表单提交,请求主体的大小会更大,且请求处理过程也会更加复杂。因此,在上 文件 时,需要谨慎考虑数据大小和性能方面的问题,以避免对服务器造成过大的负担。