第十三章 手动创建 REST 服务(一)

第十三章 手动创建 REST 服务(一)

本附录描述了如何通过继承 %CSP.REST 类来手动创建 REST 服务;此过程创建了一个手动编码的 REST 服务,它不能与所有 API 管理工具一起使用。

手动创建 REST 服务的基础知识

要手动定义 REST 服务,请执行以下操作:

  • 创建一个 REST 服务类 — %CSP.REST 的子类。在子类中:
    • 定义一个 URL 映射,该映射指定为 REST URLHTTP 方法执行的 IRIS 方法。
    • 可以选择指定 UseSession 参数。此参数控制每个 REST 调用是在其自己的 Web 会话下执行还是与其他 REST 调用共享一个会话。
    • (可选)覆盖错误处理方法。

如果想将实现代码与调度代码分开,可以在单独的类中定义实现 REST 服务的方法,并从 URL 映射中调用这些方法。

  • 定义一个使用 REST 服务类作为其调度类的 Web 应用程序。

要定义 Web 应用程序及其安全性,请转至 Web 应用程序页面(单击System Administration > Security > Applications > Web Applications)。

定义 Web 应用程序时,将 Dispatch Class 设置为 REST 服务类的名称。

此外,将应用程序的名称指定为 REST 调用的 URL 的第一部分。示例名称为 /csp/mynamespace/csp/myapp,但可以指定 URL 中允许的任何文本。

可以在一个命名空间中定义多个 REST 服务类。每个拥有自己入口点的 REST 服务类都必须拥有自己的 Web 应用程序。

创建 URL 映射

REST 服务类中,定义一个名为 UrlMapXData 块,它将 REST 调用与实现该服务的方法相关联。它可以直接将调用发送到基于 URL 内容的方法,也可以将调用转发到基于 URL 的另一个 REST 服务类。如果 Web 应用程序正在处理少量相关服务,可以将调用直接发送到实现它的方法。但是,如果 Web 应用程序正在处理大量不同的服务,可以定义单独的 REST 服务类,每个类都处理一组相关的服务。然后将 Web 应用程序配置为使用中央 REST 服务类,该类将 REST 调用转发到其他适当的 REST 服务类。

如果 %CSP.REST 的子类将调用直接发送到方法,则 URLMap 包含一个 <Route>定义,其中包含一系列 <Route> 元素。每个 <Route> 元素指定一个类方法,为指定的 URLHTTP 操作调用。通常 REST 使用 GETPOSTPUTDELETE 操作,但可以指定任何 HTTP 操作。 URL 可以选择包含作为 REST URL 的一部分指定并作为参数传递给指定方法的参数。

如果 %CSP.REST 的子类将调用转发到 %CSP.REST 的其他子类,则 UrlMap 包含一个 <Route> 定义,其中包含一系列 <Route> 元素。 <Route> 元素将具有指定前缀的所有调用转发到另一个 REST 服务类,然后该服务类将实现该行为。它可以通过将调用直接发送到方法或将其转发到另一个子类来实现该行为。

重要提示:IRIS 将传入的 REST URL 与每个<Route>URL 属性和每个 <Map>Prefix 属性进行比较,从 URL 映射中的第一项开始,并在使用相同 HTTP 的第一个可能匹配处停止请求方法。因此<Route> 中元素的顺序很重要。如果传入的 URL 可以匹配 URL 映射的多个元素,IRIS 使用第一个匹配元素并忽略任何后续可能的匹配。

带有 <Route> 元素的 URLMap

IRIS 将传入的 URLHTTP 请求方法与 URL 映射中的每个 <Route>元素进行比较。它调用在第一个匹配的 <Route> 元素中指定的方法。<Route> 元素包含三个部分:

  • Url — 指定调用 REST 服务的 REST URL 的最后一部分的格式。 Url 由文本元素和以:(冒号)开头的参数组成。
  • Method — 指定 REST 调用的 HTTP 请求方法:通常是 GET、POST、PUT 或 DELETE,但可以使用任何 HTTP 请求方法。应该选择适合服务正在执行的功能的请求方法,但 %CSP.REST 类不会对不同方法执行任何特殊处理。应该以全部大写字母指定 HTTP 请求方法。
  • Call — 指定调用以执行 REST 服务的类方法。默认情况下,此类方法在 REST 服务类中定义,但可以显式指定任何类方法。

例如,考虑以下 <Route>:

<Route Url="/echo" Method="POST" Call="Echo" Cors="false" />

这指定 REST 调用将以 /echo 结束并使用 POST 方法。它将调用定义 REST 服务的 REST.DocServer 类中的 Echo 类方法。 Cors 属性是可选的。

完整的 REST URL 由以下部分组成:

  • IRIS 服务器的服务器名称和端口。在本章中,示例中使用了服务器名称和端口 http://localhost:52773/
  • Web 应用程序页面上定义的 Web 应用程序的名称(单击System Administration > Security > Applications > Web Applications)。 (例如,/csp/samples/docserver)
  • <Route>元素的 Url 属性。如果 Url 属性的一段前面有一个 :(冒号),则它表示一个参数。参数将匹配该 URL 段中的任何值。该值作为参数传递给方法。

对于前面的示例,TCP 跟踪实用程序显示的完整 REST 调用是:

POST /csp/samples/docserver/echo HTTP/1.1
Host: localhost:52773

如果要将实现 REST 服务的代码与 %CSP.REST 调度代码分开,可以在另一个类中定义实现 REST 服务的方法,并在 Call 元素中指定类和方法。

指定参数

以下 <Route> 定义在 URL 中定义了两个参数,命名空间和类:

<Route Url="/class/:namespace/:classname" Method="GET" Call="GetClass" />

REST 调用 URL/csp/samples/docserver/class/ 开头,URL 的下两个元素指定两个参数。 GetClass() 方法将这些参数用作您要查询的命名空间和类名。例如,考虑这个 REST 调用:

http://localhost:52773/csp/samples/docserver/class/samples/Cinema.Review

REST 调用调用 GetClass() 方法并将字符串“samples”“Cinema.Review”作为参数值传递。 GetClass() 方法具有以下签名:

/// 此方法返回命名类的类文本
ClassMethod GetClass(pNamespace As %String,
                     pClassname As %String) As %Status
{

为单个 URL指定多个路由

对于给定的 URL,可以支持不同的 HTTP 请求方法。可以通过为每个 HTTP 请求定义单独的 ObjectScript 方法,或使用检查请求的单个 ObjectScript 方法来实现。

以下示例对单个 URL 的每个 HTTP 请求方法使用不同的方法:

<Route Url="/request" Method="GET" Call="GetRequest" />
<Route Url="/request" Method="POST" Call="PostRequest" />

使用这些路由,如果使用 HTTP GET 方法调用 URL /csp/samples/docserver/request,则会调用 GetRequest() 方法。如果使用 HTTP POST 方法调用它,则调用 PostRequest() 方法。

相反,可以使用以下 <Route> 定义:

<Route Url="/request" Method="GET" Call="Request" />
<Route Url="/request" Method="POST" Call="Request" />

在这种情况下,Request() 方法处理对 GETPOST 操作的调用。该方法检查 %request 对象,它是 %CSP.Request 的一个实例。在此对象中,URL 属性包含 URL 的文本。

路由图中的正则表达式

可以在路线图中使用正则表达式。 建议仅在没有其他方法来定义 REST服务以满足需求时才这样做。

在内部,用于在 URL 中定义参数的:parameter-name 语法是使用正则表达式实现的。指定为 :parameter-name 的每个段都转换为包含重复匹配组的正则表达式,特别是 ([^/]+) 正则表达式。此语法匹配任何字符串(长度非零),只要该字符串不包含 /(斜杠)字符。因此 GetClass() 示例,即 Url="/class/:namespace/:classname",等效于:

<Route Url="/class/([^/]+)/([^/]+)" Method="GET" Call="GetClass" />

其中有两个匹配组指定了两个参数。

在大多数情况下,这种格式提供了足够的灵活性来指定 REST URL,但高级用户可以直接在路由定义中使用正则表达式格式。 URL 必须与正则表达式匹配,并且由一对括号指定的每个匹配组定义一个要传递给该方法的参数。

例如,考虑以下路线图:

<Routes>
<Route Url="/Move/:direction" Method="GET" Call="Move" />
<Route Url="/Move2/(east|west|north|south)" Method="GET" Call="Move" />
</Routes>

对于第一个路由,参数可以有任何值。无论参数有什么值,都会调用 Move() 方法。对于第二条路线,参数必须是东西北或南之一;如果您使用其他参数值调用第二个路由,则不会调用 Move() 方法,并且 REST 服务会返回 404 错误,因为找不到资源。

这个简单的例子只是为了演示常用参数语法和正则表达式之间的区别。在此处讨论的情况下,不需要正则表达式,因为 Move() 方法可以(并且应该)检查参数的值并做出适当的响应。但是,在以下情况下,正则表达式很有帮助:

如果参数是可选的。在这种情况下,请使用正则表达式 ([^/]*) 而不是 :parameter-name 语法。例如:

<Route Url="/Test3/([^/]*)" Method="GET" Call="Test"/>

当然,被调用的方法也必须能够处理参数的空值。

  • 如果参数是最后一个参数并且其值可以包含斜杠。在这种情况下,如果需要参数,请使用正则表达式 ((?s).+) 而不是 :parameter-name 语法。例如:
<Route Url="/Test4/((?s).+)" Method="GET" Call="Test"/>

或者,如果此参数是可选的,请使用正则表达式 ((?s).*) 而不是 :parameter-name 语法。例如:

<Route Url="/Test5/((?s).*)" Method="GET" Call="Test"/>

带有 <Map> 元素的 URLMap

IRIS 将传入 URLURL 映射中每个 <Map> 元素中的前缀进行比较。它将传入的 REST 调用转发到第一个匹配的 <Map> 元素中指定的 REST 服务类。该类处理 URL 的其余部分,通常调用实现服务的方法。 <Map> 元素有两个属性:

  • Prefix前缀 - 指定要匹配的 URL 段。传入的 URL 通常在匹配段之后有其他段。
  • Forward后缀 - 指定将处理匹配段之后的 URL 段的另一个 REST 服务类。

考虑以下包含三个 <Map> 元素的 URLMap

XData UrlMap
{
  <Routes>
    <Map Prefix="/coffee/sales" Forward="MyLib.coffee.SalesREST"/>
    <Map Prefix="/coffee/repairs" Forward="MyLib.coffee.RepairsREST"/>
    <Map Prefix="/coffee" Forward="MyLib.coffee.MiscREST"/>
  </Routes>
}

UrlMapREST 调用转发到三个 REST 服务类之一:MyLib.coffee.SalesRESTMyLib.coffee.RepairsRESTMyLib.coffee.MiscREST

调用这些 REST 服务之一的完整 REST URL 包含以下部分:

  • IRIS 服务器的服务器名称和端口,例如 http://localhost:52773/
  • Web 应用程序页面上定义的 Web 应用程序名称(单击System Administration > Security > Applications > Web Applications)。例如,这些 REST 调用的 Web 应用程序可以命名为 /coffeeRESTSvr
  • <Map>元素的前缀。
  • REST URL 的其余部分。这是接收转发的 REST 请求的 REST 服务类将处理的 URL

例如,以下 REST 调用:

http://localhost:52773/coffeeRESTSvr/coffee/sales/reports/id/875

匹配带有前缀 /coffee/sales 的第一个 <Map> 并将 REST 调用转发到 MyLib.coffee.SalesREST 类。该类将查找 URL 其余部分的匹配项,“/reports/id/875”

作为另一个示例,以下 REST 调用:

http://localhost:52773/coffeeRESTSvr/coffee/inventory/machinetype/drip

匹配带有前缀 /coffee 的第三个 <Map> 并将 RES 调用转发到 MyLib.coffee.MiscREST 类。该类将查找 URL 其余部分的匹配项,“/inventory/machinetype/drip”

注意:在此 URLMap 示例中,如果带有前缀="/coffee"<Map> 是第一个映射,则所有带有 /coffeeREST 调用将被转发到 .coffee.MiscREST 类,即使它们匹配以下之一 <Map> 元素。 <Routes> 中的 <Routes>元素的顺序很重要。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355

推荐阅读更多精彩内容