ToB企服应用市场:ToB评测及商务社交产业平台

标题: mORMot 1.18 第18章 使用REST/JSON的客户端/服务器 [打印本页]

作者: 冬雨财经    时间: 2024-5-19 00:57
标题: mORMot 1.18 第18章 使用REST/JSON的客户端/服务器
mORMot 1.18 第十八章 使用REST/JSON的客户端/服务器

JSON是一种被多种语言和众多领先公司担当的尺度。正如我们在JSON章节中所表明的,它是尺度化的,紧凑且解析速度快,同时当加入非关键性空格时,也易于人类阅读。这些毕竟使其成为数据交换最受欢迎的格式之一。
JSON支持六种数据类型:
JSON类型描述数字JavaScript中的双精度浮点数格式,通常取决于具体实现。没有特定的整数类型字符串双引号括起来的Unicode,带有反斜杠转义布尔值true 或 false数组一个有序的值序列,以逗号分隔并括在方括号中;这些值不必要是同一类型对象一个无序的"键值对"集合,使用':'字符分隔键(Key)和值(Value),这些键值对被逗号分隔并包含在大括号中;其中的键必须是字符串且应该各不相同。null空值/未定义的值布局性字符包罗大括号{}、中括号[]、冒号:和逗号,。当你查看示例时,你会发现像电话号码如许的复杂格式可以简单地视为字符串处理。
比如:
  1. {
  2.         "firstName": "John",
  3.         "lastName": "Smith",
  4.         "age": 25,
  5.         "address": {
  6.                 "streetAddress": "21 2nd Street",
  7.                 "city": "New York",
  8.                 "state": "NY",
  9.                 "postalCode": 10021
  10.         },
  11.         "phoneNumbers": [{
  12.                         "type": "home",
  13.                         "number": "212 555-1234"
  14.                 },
  15.                 {
  16.                         "type": "fax",
  17.                         "number": "646 555-4567"
  18.                 }
  19.         ]
  20. }
复制代码
JSON的默认编码是UTF8,与SQLite3和EWB相同。这允许存储和传输完备的Unicode字符集在客户端和服务器之间。
当我们必要存储或传输二进制BLOBs时,使用Base64编码。
下表描述了Pascal变量是怎样转换的:
Pascal类型备注Boolean序列化为JSON布尔值byte, word, integer, cardinal, Int64, single, double, currency序列化为JSON数字string, RawUTF8, SynUnicode, WideString序列化为JSON字符串DateTime, TTimeLog序列化为JSON文本,编码为ISO 8601RawByteString序列化为JSON的null或Base64编码的JSON字符串RawJSON存储为未序列化的原始JSON内容(例如任何值、对象或数组)TGUIDGUID序列化为JSON文本嵌套记录序列化为JSON对象,标识为record ... end; 或 { ... },包含其嵌套定义嵌套注册记录序列化为与定义的回调相对应的JSON记录的动态数组序列化为JSON数组,标识为array of ... 或 [ ... ]简单类型的动态数组序列化为JSON数组,例如标识为array of integer静态数组序列化为JSON数组,通过增强的RTTI处理,尚未通过文本定义处理Variant序列化为JSON,完全支持TDocVariant自定义变体类型18.1 REST

REST(表征状态转移)是一种从客户端向服务器请求/传输信息,并从服务器返回信息到客户端的计谋。
使用REST时,你会用到URI(唯一资源标识符)来标识资源。
例如:
客户数据URI获取名为“dupont”的客户的详细信息http://www.mysite.com/Customer/dupont获取名为“smith”的客户的详细信息http://www.mysite.com/Customer/smith获取名为“dupont”的客户所下的订单http://www.mysite.com/Customer/dupont/Orders获取名为“smith”的客户所下的订单http://www.mysite.com/Customer/smith/Orders实际上,叫“Dupont”和“Smith”的人很多,以是通常人们会使用像客户编号、十六进制值或GUID如许的唯一ID。
CRUD操作的接口包罗POST、GET、PUT和DELETE。
HTTP方法操作GET列出集合中的一个或多个成员PUT更新集合中的一个成员POST在集合中创建一个新条目DELETE删除集合中的一个成员表征是我们描述对象的方式,通常使用JSON或XML来完成。
XML表征:
  1. <Customer>
  2.   <ID>1234</ID>
  3.   <Name>Dupond</Name>
  4.   <Address>Tree street</Address>
  5. </Customer>
复制代码
相同的JSON表征:
  1. {"Customer": {"Name":"Dupond", "Address":"Tree street"}}
复制代码
使用XML或JSON通过POST添加记录将返回刚刚创建的ID。
无状态意味着每个请求都是独立的。这意味着服务器甚至可以在请求之间重新启动,或者负载均衡器可以将请求转发到差异的实际主机。服务器不维护任何形式的状态表,如会话变量等。
结果是更精简、更高效、更可扩展的服务器或集群。
18.2 RESTful mORMot

当一个体系实现了非常靠近纯粹REST的东西时,该体系被称为RESTful体系。
mORMot可以使用HTTP/HTTPS,但它也实用于使用Windows安全模子的命名管道。
它还可以使用另一种不必要使用昂贵的证书及其迟钝握手的加密形式——这是谷歌也曾描述过的一个话题。这对于封闭的mORMot客户端(多平台)和服务器体系非常有用。但你仍然可以访问基于尺度的更慢、更常见的版本。
mORMot允许以下非尺度功能来加快对记录的访问。
它们是可选的。
BLOBs通过单独的事务处理,使用的URI类似于ModelRoot/TableName/TableID/BlobFieldName。
如许做的优点是能够使用高效的二进制传输,而将BLOBs存储在JSON中大约必要两倍的空间/数据/时间。
18.3 传输方式的选择

传输方式是指客户端和服务器之间通讯使用的方法。目前,mORMot支持四种传输方式:
比力这些方法:
历程内(In-process)Windows消息(Messages)命名管道(Named Pipe)HTTP/HTTPS实现单元(Unit)mormot.pasmormot.pasmormot.pas速度(Speed)最快(fastest)极快(extremely fast)很快(very fast)快(fast)扩展性(Scaling)最佳(受限于RAM)(Best limited by RAM)较差(例如10)(poor eg. 10)较差(poor)非常好(Very good)托管(Hosting)单一历程(one process)单一计算机(one computer)局域网/互联网(LAN/Internet)内网(intranet)协议(Protocol)方法调用(method call)WM_COPYDATA\\pc\mOrmothttps://pc/...数据(Data)JSONJSONJSONJSON服务(Service)是(Yes)否(No)是(Yes)是(Yes)客户端(Client)TSQLRestClientDBTSQL服务器(Server)TSQLRestServerDBTSQLRestServerDBTSQLRestServerDBTSQLRestServerDBExportServerExportServerMessageExportServer NamedPipeTSQLHttpWindows消息版本通常不太实用,因为包罗服务器历程在内的所有应用步伐必须处于图形用户界面(GUI)模式,而且都在同一台呆板上运行。
命名管道在通讯中曾很受欢迎,但从Windows Vista开始,对命名管道的局域网访问默认是关闭的,因此您必须手动启用它。
HTTP/HTTPS是一个很好的通用解决方案。它被普遍担当,具有良好的扩展性,而且已经过每台服务器凌驾50,000个连接的测试。通讯速度仍然很快。
请注意,甚至可以同时使用多种协议。例如,使用历程内通讯来完成某些任务,同时也提供局域网或HTTP版本的服务。
18.4 HTTP/HTTPS 传输

以下是怎样使用HTTP初始化数据库的方法。
  1. Model := CreateSampleModel;
  2. DBServer := TSQLRestServerDB.Create( Model,ChangeFileExt( paramstr(0), '.db3'),true);
  3. DBServer.CreateMissingTables;
  4. HttpServer := TSQLHttpServer.Create('8080', [DBServer],'+', HTTP_DEFAULT_MODE);
复制代码
通常,您还可以使用以下行允许跨站点的AJAX查询:
  1. HttpServer.AccessControlAllowOrigin := '*'; // 允许跨站点AJAX查询
复制代码
您通常会使用以下设置进行域名重定向:
  1. HttpServer.DomainHostRedirect('project.com','root'); // 'root' 是当前的 Model.Root
  2. HttpServer.DomainHostRedirect('blog.project.com','root/blog'); // MVC 应用程序
复制代码
包含三种类型的服务器,但荣幸的是,mORMot 可以简单地从最快的选项故障转移到最兼容的选项,只要是被允许的:
18.5 HTTPS

要启用 HTTPS,您必须在 TSQLHttpServer.Create() 构造函数的 aHttpServerSecurity 参数中设置 secSSL。
您还必要证书。您可以使用本地证书颁发机构或商业机构之一。这些按照 Windows IIS 的通常方式安装。
mORMot 网站包含当前所有操作体系的该过程的最新说明。
18.6 AES加密 - HTTPS的替代方案

AES是一种加密选项,不必要分发SSL的PKI对。
首先,积极的一面是:
不利的一面是:
如果你能忍受这些限制,AES是一个很好的选择。
在服务器上,可以通过secSynShaAes启用它。
  1. CompressShaAesSetKey('Gudmw324daJKLAF(*\&' );
  2. MyServer := TSQLHttpServer.Create(
  3. '888',[DataBase],'+',useHttpApi,32,secSynShaAes);
复制代码
在客户端上,你只需将Compression属性设置为hcSynShaAes。
  1. CompressShaAesSetKey('Gudmw324daJKLAF')
  2. MyClient.Compression := [hcSynShaAes];
复制代码
你还应该考虑压缩,因为它可以通过减少可用于收集信息的信息内容(例如数据包大小)来提高安全性。
18.7 压缩

压缩有几个目标:
你可以单独启用一种压缩或另一种压缩。我建议同时启用两者,如许当SynLZ可用时,mORMot将使用SynLZ进行压缩,否则默认使用Deflate,并完全基于尺度。
  1. MyClient.Compression := [hcSynLZ,hcDeflate];
复制代码
18.8 示例

以下是一个在8080端口上实现HTTP协议的极简数据库服务器。
  1. program cssimpleserver;
  2. {$APPTYPE CONSOLE}
  3. uses
  4.   SysUtils,
  5.   SynCommons, mORMot, mORMotSQLite3, SynSQLite3Static,  // 引入必要的单元
  6.   mORMotHttpServer,
  7.   csclass in 'csclass.pas';
  8. var
  9.   Model: TSQLModel;          // SQL模型变量
  10.   DB: TSQLRestServerDB;      // 数据库变量
  11.   Server: TSQLHttpServer;    // HTTP服务器变量
  12.   s: string;                 // 字符串变量
  13. procedure Start;
  14. begin
  15.   Model := CreateSampleModel;            // 创建样本模型
  16.   DB := TSQLRestServerDB.Create(Model, 'd:\cstest.db3', true);  // 创建数据库连接
  17.   DB.CreateMissingTables;                // 创建缺失的表
  18.   Server := TSQLHttpServer.Create('8080', [DB], '+', HTTP_DEFAULT_MODE);  // 在8080端口上创建HTTP服务器
  19.   Server.AccessControlAllowOrigin := '*'; // 设置跨域资源共享策略,允许任何来源的请求
  20. end;
  21. procedure Stop;
  22. begin
  23.   Server.Free;  // 释放HTTP服务器资源
  24.   DB.Free;      // 释放数据库资源
  25.   Model.Free;   // 释放模型资源
  26. end;
  27. begin
  28.   try
  29.     Start;                 // 启动服务器
  30.     writeln('按"Enter回车"键退出');  // 提示用户按回车键退出
  31.     readln(s);             // 读取用户输入,等待用户按下回车键
  32.   except
  33.     on E: Exception do     // 异常处理
  34.       writeln(E.ClassName, ': ', E.Message);  // 输出异常类型和异常信息
  35.   end;
  36.   Stop;                    // 停止服务器并释放资源
  37. end.
复制代码
注释说明:
它使用了一个小的TSQLRecord派生类:
  1. program cssimpleserver;
  2. {$APPTYPE CONSOLE}
  3. uses
  4.   System.SysUtils,
  5.   SynCommons, mORMot, mORMotSQLite3, SynSQLite3Static,  // 引入必要的单元
  6.   mORMotHttpServer,
  7.   csclass in 'csclass.pas';
  8. var
  9.   Model: TSQLModel;          // SQL模型变量
  10.   DB: TSQLRestServerDB;      // 数据库变量
  11.   Server: TSQLHttpServer;    // HTTP服务器变量
  12.   s: string;                 // 字符串变量
  13. procedure Start;
  14. begin
  15.   Model := CreateSampleModel;            // 创建样本模型
  16.   DB := TSQLRestServerDB.Create(Model, 'd:\cstest.db3', true);  // 创建数据库连接
  17.   DB.CreateMissingTables;                // 创建缺失的表
  18.   Server := TSQLHttpServer.Create('8080', [DB], '+', HTTP_DEFAULT_MODE);  // 在8080端口上创建HTTP服务器
  19.   Server.AccessControlAllowOrigin := '*'; // 设置跨域资源共享策略,允许任何来源的请求
  20. end;
  21. procedure Stop;
  22. begin
  23.   Server.Free;  // 释放HTTP服务器资源
  24.   DB.Free;      // 释放数据库资源
  25.   Model.Free;   // 释放模型资源
  26. end;
  27. begin
  28.   try
  29.     Start;                 // 启动服务器
  30.     writeln('press return to exit');  // 提示用户按回车键退出
  31.     readln(s);             // 读取用户输入,等待用户按下回车键
  32.   except
  33.     on E: Exception do     // 异常处理
  34.       writeln(E.ClassName, ': ', E.Message);  // 输出异常类型和异常信息
  35.   end;
  36.   Stop;                    // 停止服务器并释放资源
  37. end.
复制代码
注释说明:
这个客户端也很简单。
  1. {$APPTYPE CONSOLE}
  2. uses
  3.   System.SysUtils,
  4.   SynCommons, mORMot, mORMothttpclient,  // 引入必要的单元
  5.   csclass in 'csclass.pas';
  6. var
  7.   Model: TSQLModel;          // 定义SQL模型变量
  8.   DB: TSQLHttpClient;        // 定义HTTP客户端数据库连接变量
  9.   s: string;                 // 定义字符串变量
  10. procedure Start;
  11. var
  12.   Server: AnsiString;        // 定义服务器地址变量
  13. begin
  14.   if ParamCount = 0 then      // 如果没有传入命令行参数
  15.     Server := 'localhost'     // 则默认服务器为本地
  16.   else
  17.     Server := AnsiString(Paramstr(1));  // 否则取第一个命令行参数为服务器地址
  18.   Model := CreateSampleModel; // 创建样本模型
  19.   DB := TSQLHttpClient.Create(Server, '8080', Model);  // 创建HTTP客户端数据库连接
  20.   DB.SetUser('User', 'synopse');  // 设置数据库用户
  21. end;
  22. procedure Stop;
  23. begin
  24.   DB.Free;  // 释放数据库连接
  25.   Model.Free;  // 释放模型
  26. end;
  27. // 读取指定用户的记录
  28. procedure readone(user: string);
  29. var
  30.   rec: TSQLSampleRecord;
  31.   res: string;
  32. begin
  33.   try
  34.     rec := TSQLSampleRecord.Create(DB, 'Name = ?', [StringToUTF8(user)]);
  35.     if rec.ID = 0 then
  36.       res := 'Not found'
  37.     else
  38.       res := UTF8ToString(rec.Question);
  39.     writeln('Question for ', user, ' is ', res);
  40.   finally
  41.     rec.Free;
  42.   end;
  43. end;
  44. // 写入指定用户的记录
  45. procedure writeone(user, Question: string);
  46. var
  47.   rec: TSQLSampleRecord;
  48. begin
  49.   try
  50.     rec := TSQLSampleRecord.Create;
  51.     rec.Name := StringToUTF8(user);
  52.     rec.Question := StringToUTF8(Question);
  53.     if DB.Add(rec, True) = 0 then
  54.       writeln('ERROR: adding message to db!')
  55.     else
  56.       writeln('message added.')
  57.   finally
  58.     rec.Free;
  59.   end;
  60. end;
  61. var
  62.   user: string;  // 定义用户名字符串变量
  63. begin
  64.   try
  65.     Start;  // 启动程序
  66.     user := 'erick';  // 设置用户名为erick
  67.     readone(user);   // 读取用户记录
  68.     writeone(user, 'Happy Day');  // 写入用户记录
  69.     readone(user);  // 再次读取用户记录
  70.   except
  71.     on E: Exception do  // 异常处理
  72.       writeln(E.ClassName, ': ', E.Message);  // 输出异常类名和异常信息
  73.   end;
  74.   Stop;  // 停止程序
  75. end.
复制代码
注释说明:
注意:本文由hieroly翻译于2024年04月26日

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4