一,简介
REST风格接口是以http为传输协议,以xml或json或text为有效负载。下图展示了REST到XI再返回的一个过程,一个REST接口包含的信息有:服务URL、URL中带的参数、http方法(post/get/put等)、http头部、body部分的有效载荷。而XI内部处理中主要包含XI消息头部和body载荷。
在HTTP call转换到XI mesage时:有效负载部分会直接转移到XI的载荷,也可选择转换例如JSON格式转换为XML,而其他部分如url和operation等等会映射到预定义的XI头部变量。
二,Inbound REST service 提供REST服务
本小节我们描述一个通过PI提供REST接口服务的场景,一个外围系统通过http call调用进入到PI时,PI将选择一个sender channel处理入栈调用,下图展示了在sender channel一端使用REST适配器将接收到的HTTP call最终转化为XI消息的过程。
2.1 Channe Selection
一个HTTP call入栈时PI会根据URL、HttpOperation甚至PayloadContent来决定使用哪个sender channel。
在sender channel的Channel Selection页签配置了channel确定的一系列参数
URL :HTTP://myhost:myport/RESTAdapter/API/V2.0/{resource}/{id}?operation={opname}
url前面红色部分是固定的,所有PI提供的REST API都以此作为URL开头,后面Endpoint部分是可选的,当然还是配上比较好使得channel的dispatch更加准确。
上图Endpoint维护基本上也是固定值(上面青色这段)
还可以使用模式匹配的方式支持动态的URL(在2.3节维护橙色部分 注意绿色部分QueryString不要维护到URL pattern之中),通过{placeholder}来代替动态部分
如下两个url都会进入到同一个sender channel
…/RESTAdapter/API/V2.0/customer/123?operation=create
…/RESTAdapter/API/V2.0/order/222?operation=delete
但是下面url缺少{id},不会对应到这个sender channel
…/RESTAdapter/API/V2.0/order?operation=create
HttpOperation:http方法GET POST PUT DELETE
如果两个sender channel的endpoint部分相同,还可以根据http call使用的方法来决定分配哪个channel,如上图蓝框部分
Payload Content
还可根据Payload中部分标签的值来决定channel,如上图黄框部分,Payload为JSON或XML时给出了不同的配置框
2.2 Payload convertion
REST的负载可以是xml或者非结构化文本,但大都情况下是JSON,如果需要对负载消息进行更复杂的处理比如字段mapping,则需要将入栈JSON需要转换为XML,如果是同步接口中还要将响应的XML转换为出栈JSON。
Payload转换的配置都在sender channel的General页签下,InputMsgFormat部分是将入栈Payload转化为XI message的一些配置
DataFormat:通常REST的入栈负载格式为JSON
CharacterSet:ManualValue就是写死一个值如图UTF-8,还可从http call其他部分取到如HttpHeader、GetVariable等等
ConvertToXML:json转换为PI内部XML格式,如果不做字段mapping而将整个报文作为字符串扔给对方接口这里可不转换
AddWrapperElement:例如{"id":1,"xingming":"李四"}其两个元素都在第一层级,但是XML中只允许有且仅有一个根元素,所以这种情况下需要为XML增加一个根元素作为包裹
ElementName / ElementNamespace:勾选了上面AddWrapEle这里就必填了,这里指定ERS里面配置的MessageType及其命名空间,根据这个显式指定来生成XML根元素。
InvalidCharacter:对于不合规的element名,进行字符替代等处理
OutputMsgFormat:是用于将Response数据转换为目标格式并出栈,只有在QoS为BestEffort时才有Response
DataFormat:将XI格式的Response消息转化为何种目标格式
ConvertXMLPayloadtoJSON:不勾会把XI格式响应以字符串的形式返回给调用者吗?
StripOuterElement:对应与InputMsgFormat中的WrapperElement配置,转换时忽略XML根元素
RemoveInvalidCharacter:对应InputMsgFormat中InvalidCharacter配置
XML/JSON Namespace Mapping:该配置同时针对InputMsgFormat和OutputMsgFormat,将XML命名空间转化为JSON前缀
Custome XML/JSON Conversion Rules:只针对Response消息由XI转JSON时,下面详述:
在内部RestAdapter使用jettison库来实现两种格式的转换,默认情况下转换逻辑只是根据jettison处理器自己的优化和类型机制,没有考虑到负载所对应的MessageType中所设置的各种属性。这样转换的结果可能有时候不符合要求。
如果一个xml元素定义为一个数组,而恰好实际负载中该数组只有一行,jettison可能将其转化为非数组
如果一个xml元素定义为一个字符串,而恰好字符串的值只包含数字字符,很可能被转化为一个整数类型(json中字符串用双引号,数值不用)
假设有如下MessageType和一个真实的xml负载内容,注意这是一个response消息
MessageType | XML消息负载 |
在REST sender channel中使用标准配置,将会得到如下的json响应内容。该json就出现了上述问题:ID字段被解析为数值型,而MesasgeType中它是string所以应该用双引号;Property是一个数组,其应该转化为"Property":[{"Name":"hsjfew","Value":"hkhuew"}]
在sender channel中可以设置针对具体的标签使用特别的转换规则,如下图我们给标签ID指明了数据类型为string,为标签Property指明了其为数组,默认值的指定可能为了一些空值不出现的标签。
另外XML的命名空间和前缀就可以从xml中找到,命名空间的决定因素参考笔记MessageMapping操作第五小节
类型 | XML元素类型。 以下类型是当前支持的: String, Integer, Decimal, Boolean. 只要它是有效值列表中提到的值之一,就不会区分类型值的符号。 如果没有指定值,不会应用指定的XML/JSON转换指令,而是会执行默认的Jettison处理器逻辑。 | String type string xs:string xsd:string Integer type int integer xs:integer xsd:integer Decimal type decimal numeric float xs:decimal xsd:decimal Boolean type bool boolean xs:boolean xsd:boolean |
数组类型 | XML元素是否是数组的指示符。 只要它是有效值列表中提到的值之一,就不会区分类型值的符号。 如果没有指定值,数组指示符默认为false。 | 如果是数组: 1 true yes 如果不是数组: 0 false no |
默认值 | 在XML/JSON转换失败的情况下会赋给JSON元素的值。 例如,在上面给的demo中,元素“Quantity”的值会被作为整数处理。如果原始值不能转换为整数(比如含有字母),JSON输出会得到一个默认值。在该情况下,这个值是“0”。 需要注意的是,对于默认值而言,系统不会针对在“TYPE”中指定的类型进行元素类型检查——它会被当作字符串。在这种方式下,比如,你可以指定默认值“Invalid value”给“Quantity”。系统不会提示错误,无论是在communication channel激活的时候还是REST adapter运行期间处理相关消息的时候,即便默认值和元素类型(整型)完全不匹配。记住这点,应当注意设置默认值时要保持其类型的一致性。 | Any value. 下面的值有点特别: “null” (带引号) – 被解释为字符串“null” null (无引号) – 被解释为null “” (只有引号 – 被解释为空字符串 |
2.3 Extracting information from URL/Header/Payload
从URL、HttpHeader或Payload中提取值,并对应到预定义变量或者客制化变量,这些变量会称为XI消息的头部信息,在后续处理过程中使用,比如确定PI Operation/MessageType、在IntergrationBuilder配置中决定ReceiverChannel、在MsgMapping中参与运算。
配置如下图红框部分,另外URL Pattern为EndpointURL的动态部分
DynamicAtt:可选预定义的变量(如下图红箭头),也可选客制化变量(蓝箭头)
DynAttrName:如果客制化变量就要给个名字
ValueSource:值的来源:常量、URL模式站位符(下图实例)、来自QueryString的GetVariable、HttpHeader、JSON/XML元素
Value:根据ValueSource不同,可以做不同配置
对于XML负载,使用Xpath定位xml元素,如果xml有使用命名空间,也要加上前缀,默认用dfl前缀
对于JSON负载,使用点分割的元素路径如【Flight.Airline】,数组中定位直接用元素名后接方括号0开始计数
在PI的MessageMonitor中我们能够看到最终形成的头部变量,上图中红箭头所指预定义变量最终形成下图紫框中的DynamicVariable
2.4 REST operation detection
首先要将REST operation和HTTP operation看做是两件事情,通常情况下两者是一致的,但是也可以搞些怪:例如通过如下一个http call来取得id为99的customer,通过query string来指定它是一个get REST operation
HTTP POST on http://myhost:myport/customer/99?operation=FECTH
虽然http call使用的post的方法,但是转换为XI message后在Header部分我们能看到如下operation标签内容为GET
<SAP:DynamicConfiguration xmlns:SAP="http://sap.com/xi/XI/Message/30">
<SAP:Record name="operation" namespace="http://sap.com/xi/XI/System/REST">GET</SAP:Record>
<SAP:Record name="SourceMessageType" namespace="http://sap.com/xi/XI/Message/30/routing">
Z_MT_GGO_CCS_1081_ORDER_REQ</SAP:Record>
<SAP:Record name="path" namespace="http://sap.com/xi/XI/System/REST">/</SAP:Record>
<!--...-->
</SAP:DynamicConfiguration>
2.5 Mapping to PI Interface/Operation
通常XML的入栈负载其最外层元素包含了Interface/Operation名,如果是JSON负载在转化为XML时可能需要加上这个东东。一个Sender通道可以处理多个REST URL(尤其是Dynamic url),此时需要根据入栈信息确定在XML最外层元素加上什么
Variable:就是前面2.3中涉及的预定义变量和客制化变量
Expression:固定值或Glob表达式
Operation/Namespace:在最外层XML加入节点的名字与命名空间
2.6 Send Message to PI
本阶段消息已经有Adapter Engine处理完毕,形成了XI格式消息,并发送给下一个组件处理
2.7 Error Handling
错误处理是一个可选的设置,Sender通道错误的发生比如是适配器的格式转化错误、配置错误,以及同步接口的response消息内容错误。错误的处理方式:
-
-
- Error:记录错误日志,消息传输失败
- Ignore Error:记录错误日志,消息传输成功
- Custome Result:消息传递成功,指定一个Http status code和Payload返回
-
三,Outbound REST service 调用远程REST服务
本小节的场景:SAP erp通过PI调用一个外部REST接口,我们重点关注Receiver channel处理,它会将用适配器将XI消息转化为Http请求并发往REST服务方,在同步接口时还要将Http返回转化为XI消息。
3.1 Read XI message
通过IntergrationServer处理XI格式消息来到了ReceiverChannel,主要包括HeaderVariable和Payload
3.2 Operation Rules
与2.5小节配置相对应;输入的负载为XML格式时,适配器可以从最外层元素取得Interface/Operation名,可以用这个名字映射到DynamicVariable(可用于下一步生成DynamicURL)。下表展示了Glob表达式(红色)和固定值(绿色)两种配置形式
Operation | Namespace | Variable | Value |
Customer* | http://sap.com/xi/XI/Demo/ | resource | customer |
*Create | http://sap.com/xi/XI/Demo/ | httpoperation | POST |
CustomerCreate | http://sap.com/xi/XI/Demo/ | resource | customer |
CustomerCreate | http://sap.com/xi/XI/Demo/ | httpoperation | POST |
3.3 generate Dynamic URL
在调用REST之前要确定本次调用的REST url地址
url地址可以是静态的,在下面URL pattern写死就行了。动态的url可以用占位符来替换一些动态值,替代值可以是常量、Header变量、Xpath或JSON定位元素
3.4 Determine http operation
在调用REST接口时使用的http方法,可以如下图写死,也可根据Header变量等等
3.5 Setting HTTP Header
如果REST服务方需要某些http抬头值,可以设置一个手工值或者使用占位符引用3.3小节设置的Pattern Variable值,比如有时token不放在url里面,而是放在HttpHeader
3.6 Convert Payload
涉及到请求和响应两部分的转换,如下图绿框和红框两块区域
下图示例:REST服务方要求请求负载为json格式,且其返回负载也为json格式
RequestFormat部分:将XI格式消息转化为JSON
StripOperationFromMsg:如果XI消息最外层元素为Interface/Operation信息,而REST服务端不关心该信息,可以勾选剔除
Convert XML Payload to JSON:勾选后会出现下方更多转换配置,包括图最下方Custom XML/JSON Convert Rule
ResponseFormat部分:将REST服务返回的JSON负载转化为XI格式
3.7 Calling REST service
调用远程REST服务,返回HttpStatusCode