本章总结了如何以及为什么修改REST服务的规范类。
本章假设您以前已经生成了REST服务类,如“创建和编辑REST服务”中所述。
5.1 概述
下表列出了修改规范类的原因,并简要总结了所需的更改:
原因 | 变化 |
---|---|
更新或替换规范 | 手动或通过重新生成规范类来修改OpenAPI XData块。 |
启用REST服务以支持CORS | 手动修改OpenAPI XData块;还添加一个类参数并创建一个自定义分派超类。请参阅“在REST服务中支持CORS” |
启用REST服务以支持web会话 | 添加类参数。请参阅“将Web会话用于REST”一章 |
指定使用端点所需的权限 | 手动修改OpenAPI XData块。请参阅“保护REST服务”一章 |
重写默认内容类型、响应字符集或输入流处理 | 添加类参数。请参阅本章下一节。 |
为服务方法指定非默认名称 | 手动修改OpenAPI XData块。请参阅本章中的“重写服务方法的名称”。 |
每当编译规范类时,编译器都会在同一个包中重新生成分派类并更新实现类(请参阅“InterSystems如何更新实现类”)。
5.2 覆盖内容类型、响应字符集或输入流处理
只需向规范类添加类参数并重新编译,就可以覆盖REST服务的几个关键方面。
- 默认情况下,REST服务需要application/json内容类型。要覆盖此项,请将以下内容添加到规范类:
Parameter CONTENTTYPE = "some-content-type";
其中some-content-type是MIME内容类型。
- 默认情况下,REST服务的响应消息采用UTF-8格式。要覆盖此项,请将以下内容添加到规范类:
Parameter CHARSET = "some-character-set";
这里some-character-set是字符集的名称。
- 默认情况下,REST服务将输入字符流转换为Unicode。要不执行此操作,请将以下内容添加到规范类中:
Parameter CONVERTINPUTSTREAM = 0";
然后重新编译。然后将这些更改复制到分派类。
5.3 重写服务方法的名称
默认情况下,编译器使用操作的operationId
来确定相应REST调用调用的方法的名称。您可以指定其他名称。为此,在规范类的OpenAPI XData
块中添加以下操作:
"x-ISC_ServiceMethod":"alternatename"
例如:
"/pets":{
"get":{
"description":"Returns all pets from the system that the user has access to",
"operationId":"findPets",
"x-ISC_ServiceMethod":"ReturnPets",
"produces":[
"application/json",
"application/xml",
"text/xml",
"text/html"
],
然后重新编译。然后编译器将这个新方法添加到分派和实现类中。一定要编辑实现类并为这个新方法提供一个实现。
5.4 在REST服务中支持CORS
跨源资源共享(CORS)允许在另一个域中运行的脚本访问服务。
通常,当浏览器从一个域运行脚本时,它允许对同一域进行XMLHttpRequest
调用,但在对另一个域进行调用时不允许。这种浏览器行为限制某人创建恶意脚本,以滥用机密数据。恶意脚本可能允许用户使用授予用户的权限访问另一个域中的信息,但随后,在用户未知的情况下,对机密信息进行其他使用。为了避免这个安全问题,浏览器通常不允许这种跨域
如果不使用跨源资源共享(CORS),带有访问REST服务的脚本的网页通常必须与提供REST服务的服务器位于同一域中。在某些环境中,在不同于提供REST服务的服务器的域中使用脚本的网页是有用的。CORS支持这种安排。
下面提供了浏览器如何使用CORS处理XMLHttpRequest
的简化描述:
- 域
DomOne
中网页中的脚本包含对域DomTwo
中的InterSystems IRIS REST服务的XMLHttpRequest
。XMLHttpRequest
具有CORS的自定义标头。 - 用户查看此网页并运行脚本。用户的浏览器检测到与包含网页的域不同的域的
XMLHttpRequest
。 - 用户的浏览器向InterSystems IRIS REST服务发送一个特殊请求,该请求指示
XMLHttpRequest
的HTTP请求方法和原始网页的域,在本例中为DomOne
。 - 如果请求被允许,则响应包含请求的信息。否则,响应仅包含指示CORS不允许请求的标头。
5.4.1 启用REST服务以支持COR概述
默认情况下,InterSystems REST服务不允许CORS标头。但是,您可以启用CORS支持。在REST服务中支持CORS有两个部分:
- 启用REST服务以接受部分或所有HTTP请求的CORS标头。请参阅“接受CORS标题”
- 编写代码,使REST服务检查CORS请求并决定是否继续。例如,您可以提供包含仅包含受信任脚本的域的允许列表。InterSystems IRIS为文档目的提供了一个简单的默认实现;此默认实现允许任何CORS请求。
重要:
默认的CORS标头处理不适用于处理机密数据的REST服务。
5.4.2 接受CORS 标头
要指定REST服务接受CORS标头,请执行以下操作:
-
修改规范类以包含
HandleCorsRequest
参数。要为所有调用启用CORS标头处理,请将
HandleCorsRequest
参数指定为1:Parameter HandleCorsRequest = 1;
或者,要为某些调用而不是调用启用CORS标头处理,请将
HandleCorsRequest
参数指定为""(空字符串):Parameter HandleCorsRequest = "";
-
如果将
HandleCorsRequest
参数指定为"",请编辑规范类中的OpenAPI XData
块,以指示哪些调用支持CORS。具体来说,对于操作对象,添加以下属性名称和值:"x-ISC_CORS":true
例如,
OpenAPI XData
块可能包含以下内容:"post":{ "description":"Creates a new pet in the store. Duplicates are allowed", "operationId":"addPet", "produces":[ "application/json" ], ...
添加
x-ISC_CORS
属性,如下所示:"post":{ "description":"Creates a new pet in the store. Duplicates are allowed", "operationId":"addPet", "x-ISC_CORS":true, "produces":[ "application/json" ], ...
-
编译规范类。此操作将重新生成分派类,从而导致行为的实际更改。无需详细了解分派类,但请注意以下更改:
- 它现在包含
HandleCorsRequest
参数的值。 URLMapXData
块现在包含与您修改的操作相对应的<Route>
元素的Cors=“true”
。
- 它现在包含
如果HandleCorsRequest
参数为0(默认值),则对所有调用禁用CORS标头处理。在这种情况下,如果REST服务接收到带有CORS标头的请求,则该服务拒绝该请求。
重要:
InterSystems IRIS REST服务支持OPTIONS请求(CORS预飞行请求),该请求用于确定REST服务是否支持CORS。发送此类请求的用户应该对REST服务使用的任何数据库具有READ权限。如果没有,服务将响应HTTP 404错误。在使用委托身份验证的配置中,请求将由经过身份验证的用户发送;在
ZAUTHENTICATE
例程中分配适当的权限。在不使用委托身份验证的配置中,此请求未经身份验证发送,并由CSPSystem用户执行;使用管理门户分配适当的权限。
5.4.3 定义如何处理CORS标头
当您启用REST服务接受CORS标头时,默认情况下,该服务接受任何CORS请求。REST服务应该检查CORS请求并决定是否继续。例如,您可以提供包含仅包含受信任脚本的域的允许列表。为此,您需要:
- 创建
%CSP.REST
的子类。在该类中,实现第一小节中描述的OnHandleCorsRequest()
方法。 - 修改规范类并重新编译,重新生成分派类。
最终结果是分派类继承自您的自定义类,而不是%CSP.REST
,因此使用了OnHandleCorsRequest()
的定义,该定义覆盖了默认的CORS头处理。
5.4.3.1 定义OnHandleCorsRequest()
在%CSP.REST
的子类中,定义OnHandleCorsRequest()
方法,该方法需要检查CORS请求并适当设置响应标头。
要定义此方法,您必须熟悉CORS协议的详细信息(此处未讨论)。
您还需要知道如何检查请求并设置响应标头。为此,检查默认使用的方法是有用的,%CSP.REST
的HandleDefaultCorsRequest()
方法。本节介绍了该方法如何处理源、凭据、头和请求方法,并提出了一些变化。您可以使用此信息编写OnHandleCorsRequest()
方法。
以下代码获取源并使用它设置响应标头。一种可能的变化是根据允许列表测试原点。然后允许域,设置响应标头。如果没有,请将响应标头设置为空字符串。
#; Get the origin
Set tOrigin=$Get(%request.CgiEnvs("HTTP_ORIGIN"))
#; Allow requested origin
Do ..SetResponseHeaderIfEmpty("Access-Control-Allow-Origin",tOrigin)
以下行指定应包含授权标头。
#; Set allow credentials to be true
Do ..SetResponseHeaderIfEmpty("Access-Control-Allow-Credentials","true")
以下行从传入请求中获取标头和请求方法。您的代码应该测试头和请求方法是否被允许。如果允许,请使用它们设置响应标头。如果没有,请将响应标头设置为空字符串。
#; Allow requested headers
Set tHeaders=$Get(%request.CgiEnvs("HTTP_ACCESS_CONTROL_REQUEST_HEADERS"))
Do ..SetResponseHeaderIfEmpty("Access-Control-Allow-Headers",tHeaders)
#; Allow requested method
Set tMethod=$Get(%request.CgiEnvs("HTTP_ACCESS_CONTROL_REQUEST_METHOD"))
Do ..SetResponseHeaderIfEmpty("Access-Control-Allow-Method",tMethod)
重要:
默认的CORS标头处理不适用于处理机密数据的REST服务。
5.4.3.2 修改规范类
在包含OnHandleCorsRequest()
的%CSP.REST
的自定义子类后,请执行以下操作:
-
编辑规范类中的
OpenAPI XData
块,使信息对象包含名为x-ISC_DispatchParent
的新属性。此属性的值必须是自定义类的完全限定名称。例如,假设
OpenAPI XData
块如下所示:"swagger":"2.0", "info":{ "version":"1.0.0", "title":"Swagger Petstore", "description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification", "termsOfService":"http://swagger.io/terms/", "contact":{ "name":"Swagger API Team" }, ...
假设
%CSP.REST
的自定义子类名为test.MyDispatchClass
。在这种情况下,您将按如下方式修改XData块:"swagger":"2.0", "info":{ "version":"1.0.0", "title":"Swagger Petstore", "description":"A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification", "termsOfService":"http://swagger.io/terms/", "x-ISC_DispatchParent":"test.MyDispatchClass", "contact":{ "name":"Swagger API Team" }, ...
-
编译规范类。此操作重新生成调度类。您将注意到该类现在扩展了您的自定义分派超类。因此,它将使用
OnHandleCorsRequest()
方法。
5.5 将Web会话与REST结合使用
REST的目标之一是无状态;也就是说,从一个REST调用到下一个调用,服务器上没有存储任何知识。跨REST调用保留web会话打破了无状态范式,但您可能希望保留web会话的原因有两个:
- 最小化连接时间-如果每个REST调用都创建一个新的web会话,则需要在服务器上建立一个新会话。通过保留web会话,REST调用连接速度更快。
- 跨REST调用保留数据-在某些情况下,跨REST调用保存数据可能是有效满足业务需求所必需的。
要启用在多个REST调用上使用单个web会话,请在规范类中将UseSession参数设置为1。例如:
Parameter UseSession As Integer = 1;
然后重新编译这个类。
如果UseSession为1,则InterSystems IRIS将在多个REST服务调用之间保留web会话。如果参数为0(默认值),InterSystems IRIS将为每个REST服务调用使用新的web会话。
注:
重新编译规范类时,UseSession参数会复制到分派类,这会导致行为的实际变化。