logo资料库

REST Server in Delphi XE Using DataSnap中文版.pdf

第1页 / 共58页
第2页 / 共58页
第3页 / 共58页
第4页 / 共58页
第5页 / 共58页
第6页 / 共58页
第7页 / 共58页
第8页 / 共58页
资料共58页,剩余部分请下载后查看
REST Servers in Delphi XE Using DataSnap Marco Cantù, http://blog.marcocantu.com December 2010 译: ZhaoShuLin & http://fanyi.youdao.com/ 美洲总部 加州街 100 号,12 楼 旧金山,加利福尼亚 94111 EMEA 总部 纽约办公室 约克路 18 号 Maidenhead, Berkshire SL6 1SF, United Kingdom 亚太地区总部 L7. 313 La Trobe Street Melbourne VIC 3000 Australia 第 1 页 共 58 页
EXECUTIVE SUMMARY(执行概要) 具象状态传输(Representational State Transfer, REST)是 Web 服务的一种 新体系结构,对行业产生了重大影响。来自大型供应商(谷歌、雅虎、亚马逊,现 在还有微软)的大多数新的公共 web 服务都依赖于 REST 作为共享和合并来自多 个来源的信息的技术. 由于实现 REST 体系结构意味着只使用简单的技术(如 HTTP 和 XML), Delphi 过去一直对它有很好的支持。Delphi 2010 通过 DataSnap 基础设施增加 了对 REST 的支持,Delphi XE 通过支持 WebBroker 集成和为 web 服务公开的 方法创建 JavaScript 代理,进一步推动了模型的发展。 本文深入研究了 Delphi XE 中 REST 服务器的开发,展示了如何使用盒中可 用的特性,如何使用额外的 Delphi 支持代码扩展这些特性,以及如何利用 jQuery 库。在 DataSnap 提供的各种模型中,我们的重点将是开发 Delphi REST 服务器, 并结合使用 JavaScript 和 jQuery 编写的基于浏览器的应用程序。但是要记住, 相同的 REST 服务器也可以被各种客户端使用,包括基于移动设备的应用程序. INTRODUCTION: THE CONCEPTS BEHIND REPRESENTATIONAL STATE TRANSFER (介绍:背后的概念 具象状态传输) 在过去的十年里,我们见证了网络的爆炸式发展,现在又见证了所谓的 Web 2.0。我们刚刚开始看到的是不同 web 站点之间、web 站点与客户端应用程序之 间、web 站点与业务数据库之间的自动交互——这是一种通常很难完全理解的全 局互连. 在 Web 上,数据的移动速度快于我们的浏览速度,因此对能够查找、跟踪 和监视来自不同来源的信息(如销售数据、财务信息、在线社区、营销活动等)的 程序有强烈的需求。同时,这种服务器端处理可以由定制的客户端应用程序和在 Web 浏览器中本地运行的应用程序来利用。 web 服务的概念相当抽象,当涉及到技术时,目前有两个主要的解决方案吸 引着开发人员。一个是简单对象访问协议(SOAP)的使用,参看 http://www.w3.org/tr/soap/ . 顺便提一下,Delphi 多年来一直支持 SOAP. 另一个 web 服务解决方案是使用 REST. 第 2 页 共 58 页
在本文中,我们将专门关注 REST,因为它更灵活,最适合作为客户端浏览 器应用程序(但也适用于许多其他场景)的后端。这个正式名称的引入及其背后的 理论是最近提出的。首先需要提到的是,没有一个正式的 REST 标准. REST 这个词是 Representational State Transfer 首字母缩写,最初是 Roy Fielding 在他的博士论文中创造的。这是 2000 年的一篇论文,它迅速传播开来,成为了 通过 web 使用 HTTP 和 url 访问数据的同义词,而不是依赖于 SOAP 标准. 其思想是,当您访问 web 资源(使用浏览器或特定的客户端应用程序)时,服 务器将向您发送资源的具现(HTML 页面、图像、一些原始数据……),接收到的 客户端将设置为给定状态。随着客户访问更多的信息或页面(可能使用链接),其 状态将会改变,从之前的状态转移. “具象状态传输的目的是唤起一个设计良好的Web应用程序的行为的形象: 一个网络的网页(一个虚拟的状态机),通过应用程序通过选择链接,用户的进展 (stat)的转换,导致下一个页面(代表应用程序的下一个状态)传输给用户呈现的使 用。” REST ARCHITECTURE’S KEY POINTS(REST 架构的关键点) 因此,如果 REST 是一种体系结构(或者更好的是一种体系结构样式),那么 它显然不是标准,尽管它使用了一些现有的标准,比如 HTTP、URL,以及许多 实际数据的格式类型. 与 SOAP 相比,REST 架构使用HTTP 及其数据格式(通常是 XML 或 JSON), 其格式与 SOAP 完全相同: . REST 使用 URL 来标识服务器上的资源(而 SOAP 为许多请求使用单个 URL,详细信息在 SOAP 信封中)。注意,这里的思想是使用 URL 来标识 资源,而不是资源上的操作. . REST 使用 HTTP 方法来指示执行哪个操作(检索或 HTTP GET、创建或 HTTP PUT、更新或 HTTP POST 以及删除或 HTTP 删除). . REST 使用 HTTP 参数(作为查询参数和 POST 参数)向服务器提供更多信 息. . REST 依赖 HTTP 进行身份验证、加密和安全性(使用 HTTPS). . REST 使用多种 mime 格式(XML、JSON、图像和许多其他格式)以普通 文档的形式返回数据. 第 3 页 共 58 页
在这种场景中,有很多架构元素值得考虑。REST 对系统的要求如下: . 原生的 Client/server(这里与数据库 RDBMS 无关). . 本质上无状态. . 缓存友好型(如果按顺序调用两次,相同的 URL 应该返回相同的数据,除 非服务器端数据发生更改),允许在客户端和服务器之间插入代理和缓存服 务器。一个推论是,所有 GET 操作都应该没有副作用. 关于 REST 的理论当然还有很多内容,但我希望这能让你从这个核心理论 开始。接下来的实际示例和 Delphi 代码应该会阐明主要概念 REST TECHNOLOGIES AND DELPHI 尽管已经说过没有 REST 标准,并且您不需要为 REST 开发提供特定的工具, 但是有一些现有的标准可供 REST 进行应用,这些标准值得简短地介绍一下(对 每个标准的深入描述可能需要一本书). 这里的重点是 Delphi 对这些技术的支持. 超文本传输协议是万维网的核心标准,无需介绍。诚然,HTTP 不仅可以被 Web 浏览器使用,也可以被任何其他应用程序使用. 在 Delphi 应用程序中,编写使用 HTTP 的客户端应用程序的最简单方法是 依赖 Indy HTTP 客户端组件或 IdHttp。如果您调用该组件的 Get 方法,提供 URL 作为参数,您可以检索任何 Web 页面和许多 REST 服务器的内容。有时,您可 能需要设置其他属性,提供身份验证信息,或者为 SSL 支持附加第二个组件(我 们将在一些示例中看到). 注意,为了安全起见,通常应该在线程中发出 IdHttp 请求。因为 Indy 套件 使用的是阻塞线程,所以程序的用户界面将被阻塞,直到请求返回为止(在 web 服务器速度慢或数据传输量大的情况下,这可能需要很长时间)。在本文的演示中, 我一般不会仅仅为了简单起见而使用线程,但这是推荐的方法. 在服务器端,您可以使用多个体系结构在 Delphi 中创建 web 服务器或 web 服务器扩展。您可以使用 IdHttpServer 组件创建独立的 web 服务器,也可以创 建 web 服务器扩展(CGI 应用程序、ISAPI 或 Apache 模块)。从 Delphi XE 开始, WebBroker 体系结构就支持这两种模型(而在过去仅限于 web 服务器扩展)。事实 第 4 页 共 58 页
上,当您使用 new Delphi XE 向导创建 DataSnap REST 服务器时,您将获得一 个独立的间接基于 IdHttpServer 组件的 web 服务器. JSON IN DELPHI web 服务使用 XML 或 JSON,而 Delphi REST 服务器默认使用后者。这就 是为什么我在对 Delphi 和 REST 的介绍的最后,对 JavaScript 对象 Notatation(或 JSON)的几乎不做介绍的原因。 THE JSON NOTATION(JSON 符号) JSON 是一种基于文本的符号,用于表示 JavaScript 对象,因此它们可以被 持久保存或从一个应用程序转移到另一个应用程序(或从一台计算机转移到另一 台计算机)。虽然几年前的共识是使用 XML 作为表示复杂数据结构的表示法,但 在过去几年中,JSON 变得越来越流行,因为它更紧凑,更依赖于编程语言概念, 而且在基于 JavaScript 浏览器的应用程序中非常容易解析……由于越来越多的 库和工具,大多数其他编程语言都使用这种语言。 您可以通过阅读 IEFT (Internet Engineering Task Force)的 RFC 4627 规范 或查看 JSON 官方主页来了解更多关于 JSON 的信息: http://www.ietf.org/rfc/rfc4627.txt http://json.org 您还可以继续阅读以获得简短的介绍,因为 JSON 比较容易理解,有四种基 本类型和两种结构。基本类型是数字、字符串、Booleans2(真或假)和 null 值。 两种 JSON 数据结构如下: . JSON 对象——名称和值对的集合,用花括号括起来,用逗号分隔(而每对 的两个元素被一个冒号分隔)。集合表示记录或对象。 . JSON 数组-方括号内的值列表,并用逗号分隔。列表表示数组或集合。 下面是两个符号的简单示例,一个对象有两个对(所有字符串包括对名称都 用双引号表示)和一个由两个值组成的列表,一个数字和一个字符串: { "Name":"Marco", "Value":100 } [22, "foo"] 第 5 页 共 58 页
当然,您可以随意组合这些构造,因此您可以使用对象和数组作为对的值和 数组的元素: { "Me": { "FirstName":"Marco", "LastName":"Cantù", "Wife": "Lella", "Kids": [ { "Name":"Benedetta", "Age":11 }, { "Name":"Jacopo", "Age":7 } ] }} JSON IN DELPHI 2010 虽然在过去已经有了一些用于 Delphi 的 JSON 库,但是第一个具有(对 JSON) 原生支持的版本是 Delphi 2010。原生 JSON 支持已经通过在 DBXJSON 单元中 定义的一系列类提供,即使在与 dbExpress 框架完全无关的应用程序中也可以使 用这些类(尽管名称如此--带有 DBX 字样)。 DBXJSON 单元定义了一些类,您可以使用这些类来处理从 TJSONValue 继承的各种 JSON 数据类型(不同类型的单个值、数组、对和对象): . 基值类型包括 TJSONNull、TJSONFalse、TJSONTrue、TJSONString 和 TJSONNumber。 . 数据结构包括 TJSONObject(和内部 TJSONPair)和 TJSONArray. 下面是一个从 JsonTests 项目中提取的简单代码片段,用于演示不同原语类 型的输出。注意,您创建的每个临时对象都必须手动释放,因此添加 LogAndFree 私有支持方法的想法是: procedure TFormJson.LogAndFree (jValue: TJSONValue); begin try Log (jValue.ClassName + ' > ' + jValue.ToString); finally jvalue.Free; end; 第 6 页 共 58 页
end; procedure TFormJson.btnValuesClick(Sender: TObject); begin LogAndFree (TJSONNumber.Create(22)); LogAndFree (TJSONString.Create('sample text')); LogAndFree (TJSONTrue.Create); LogAndFree (TJSONFalse.Create); LogAndFree (TJSONNull.Create); end; 这是对应的输出: TJSONNumber > 22 TJSONString > "sample text" TJSONTrue > true TJSONFalse > false TJSONNull > null 使用 DBXJSON 单元的其他类创建数组和对象同样简单。数组是一种可以添 加任何值(包括数组和对象)的结构: procedure TFormJson.btnSimpleArrayClick(Sender: TObject); var jList: TJSONArray; begin jList := TJSONArray.Create; jList.Add(22); jList.Add('foo'); jList.Add(TJSonArray.Create (TJSONTrue.Create)); (jList.Get (2) as TJSonArray).Add (100); Log (jList.ToString); jList.Free; end; JSON 输出: [22,"foo",[true,100]] 注意,JSON 容器(数组和对象)拥有它们的内部元素,因此您可以释放容器 来清理整个 JSON 值组的内存。 当您有一个对象时,您可以添加到它的唯一元素是一对(a pair),但是这个 pair 中的值可以是任何 JSON 值,包括一个嵌套的对象: procedure TFormJson.btnSimpleObjectClick(Sender: TObject); var jsonObj, subObject: TJSONObject; begin jsonObj := TJSONObject.Create; 第 7 页 共 58 页
jsonObj.AddPair(TJSONPair.Create ('Name', 'Marco')); jsonObj.AddPair(TJSONPair.Create ('Value', TJSONNumber.Create(100))); subObject := TJSONObject.Create( TJSONPair.Create ('Subvalue', 'one')); jsonObj.AddPair( TJSONPair.Create ('Object', subObject)); Log (jsonObj.ToString); jsonObj.Free; end; 这个对象的 JSON 值(带有一些手动格式以提高可读性)如下: { "Name":"Marco", "Value":100, "Object": { "Subvalue":"one" } } PARSING JSON IN DELPHI(DELPHI 解析 JSON) 使用 DBXJSON 类创建 JSON 数据结构并生成相应的 JSON 表示形式是很 有趣的,但更有趣的是您可以反过来做,即使用 JSON 表示解析字符串以创建相 应的 Delphi 对象. 一旦有了 JSON 字符串,就可以将其传递给 TJSONObject 类的 ParseJSONValue 类方法,该方法返回一个 TJSONValue 对象。在我们知道求 值返回 JSON 对象的情况下,我们必须将其转换回正确的类型。ParseJSONValue 类方法不接受字符串作为参数,但是需要一个 ASCII 或 UTF8 编码的字节数组(最 后一个特性没有包含在 Delphi 2010 中,是 XE 版本的新特性)。在这两种情况下, 我们都需要使用合适的编码类将字符串转换为字节数组: TEncoding.ASCII.GetBytes(strParam) // a string converted to ASCII TEncoding.UTF8.GetBytes(sUtf8) // any UTF8 (or Unicode) string 对于 UTF8 字符串,必须向 ParseJSONValue 方法传递额外的参数,或者调 用类似的 ParseJSONValueUTF8 方法。总的来说,btnParseObjClick 的初始部 分(仍然是 JsonTests 示例的主窗体中)如下: var strParam: string; jsonObj: TJSONObject; begin 第 8 页 共 58 页
分享到:
收藏