通用接口

通用接口层
网络传输
数据映射
控制器
操作(OTRS作为提供者)
调用程序(OTRS作为请求者)
通用接口通讯流程
OTRS作为提供者
远程请求:
OTRS响应:
OTRS作为请求者
OTRS请求:
远程响应:
Web服务
WEB服务图形界面
WEB服务概览
添加WEB服务
导入WEB服务样例
修改WEB服务
克隆WEB服务
导出WEB服务
导入WEB服务
WEB服务历史
删除WEB服务
WEB服务调试器
修改WEB服务配置
WEB服务命令行接口
WEB服务配置
配置详细信息
一般
Debugger(调试器)
Provider(提供者)
Requester(请求者)
连接器
捆绑的连接器
会话连接器
工单连接器
例子:
WEB服务配置
Perl SOAP请求者
Perl REST请求者
REST请求的cURL例子

OTRS通用接口包含一个多层框架,让OTRS能够通过一个WEB服务与其它系统通讯,这个通讯可以是双向的:

通用接口层

通用接口是基于层构建的模型,使用灵活且易于定制。

层是一个文件的集合,控制通用接口如何执行一个WEB服务的不同部分。使用正确的配置,你可以给不同的外部系统构建不同的WEB服务,而不用创建新的模块。

注意

如果远程系统不支持目前通用接口捆绑的模块,需要为那个特定的WEB服务开发特殊的模块。

OTRS自带的通用接口模块随着时间流逝会更新和增长。

图 4.112. 接口的‘层’图解

接口的‘层’图解


网络传输

本层负责与远程系统的正确通讯。它在OTRS作为提供者时接收请求并生成响应,在OTRS作为请求者时生成请求并接收响应。

提供者通讯由一个新的WEB服务处理程序“nph-genericinterface.pl”处理。

请求者通讯可以在一个通用接口模块或其它任何OTRS模块触发事件过程中初始化。这个事件由事件处理程序捕获,取决于配置,这个事件由请求者对象直接处理或委派给计划程序(一个单独的守护进程,设计来异步处理任务)处理。

数据映射

本层负责在OTRS和远程系统之间转化数据结构(内部数据和外部数据层)。通常远程系统拥有与OTRS不同的数据结构(包括不同的值和这些值的名称),这就是本层的重要性:将收到的信息转为OTRS能够理解的东西,在相反的方向上将这些信息使用远程系统的数据字典发送给每个远程系统。

示例:OTRS中的“Priority(优先级)”在远程系统中可能叫做“Prio”,它的值“1-低”(OTRS)应当映射为远程系统中的“Information”。

控制器

控制器是相似的操作或调用程序的合集。例如,一个工单控制器可能包含数个标准工单操作。可以定制控制器,例如,一个“TicketExternalCompany”控制器可能包含与标准工单控制器相似的功能,但有不同的数据接口或函数名称(适应远程系统的函数名称)或完全不同的代码。

一个通用接口应用可以与一个远程系统同步信息,只可以跟另一个相同类型的远程系统。在这种情况下,需要开发新的控制器,并且操作和调用程序必须模拟远程系统行为,这样OTRS暴露的接口就类似于远程系统的接口。

操作(OTRS作为提供者)

操作是一个能在OTRS内执行的单个动作。所有的操作有相同的编程接口,它们接收数据到一个指定的参数,并返回一个数据结构,包含成功状态、潜在的错误消息和返回数据。

通常操作使用已经映射的数据(内部)来调用核心模块并执行OTRS中的动作如:创建一个工单、更新一个用户、使一个队列无效、发送一个通知等等。一个操作有OTRS API的全部权限以执行这个动作。

调用程序(OTRS作为请求者)

调用程序是OTRS在一个远程系统上执行的动作。调用程序使用OTRS核心模块来处理和收集需要的信息以创建一个请求。当信息准备好后它必须映射到远程系统格式以便发送给远程系统,远程系统处理这个信息、执行动作并发回响应,要么处理成功要么处理错误。

通用接口通讯流程

通用接口有定义的流程来执行作为提供者和请求者的操作。

这些流程描述如下:

OTRS作为提供者

远程请求:
  1. HTTP请求

    • OTRS接收到HTTP请求并传递它。

    • 提供者模块负责执行和控制这些操作。

  2. 网络传输

    • 网络传输模块解码数据有效载荷并从剩余数据中分离操作的名称。

    • 操作名称和操作数据都返回给提供者。

  3. 外部数据

    • 从远程系统发来的数据(这不是一个基于模块的层)。

  4. 映射

    • 按这个操作指定的映射配置(进入的请求数据映射)将数据从外部系统格式转化为OTRS内部格式。

    • 已转化的数据返回给提供者。

  5. 内部数据

    • 数据已经转化并准备传递到操作(这不是一个基于模块的层)。

  6. 操作

    • 接收并验证数据。

    • 执行用户访问控制。

    • 执行操作。

OTRS响应:
  1. 操作

    • 返回结果数据到提供者。

  2. 内部数据

    • 数据从操作返回。

  3. 映射

    • 数据按映射配置中指定的映射(出站响应数据的映射)转化回远程系统的格式。

    • 已转化的数据返回给提供者。

  4. 外部数据

    • 转化的数据准备传递给网络传输作为响应。

  5. 网络传输

    • 接收远程系统格式的数据。

    • 为这个网络传输类型构建一个有效的响应。

  6. HTTP响应

    • 响应发送回WEB服务客户端。

    • 如果出现一个错误(例如SOAP错误、HTTP错误等等),发送一个错误响应给远程系统。

OTRS作为请求者

OTRS请求:
  1. 事件触发器处理程序

    • 基于WEB服务配置确定请求是同步还是异步。

      • 同步

        • 直接调用请求者以便创建一个新的请求,并通过这个层传递。

      • 异步

        • 为OTRS守护进程创建一个新的通用接口(请求者)任务,通过委派该请求执行到计划程序进程,大大改善了用户体验。否则准备该请求和远程执行需要的所有时间都会加到触发这些请求的OTRS事件上。

        • 在下一个循环中OTRS守护进程读取新任务并创建一个到请求者的调用,请求者会创建一个新的请求并通过这个层传递它。

  2. 调用程序

    • 接收来自事件的数据。

    • 验证收到的数据(如果需要)。

    • 调用核心模块来补足数据(如果需要)。

    • 返回请求数据结构,或发送一个中止通讯信号给请求者以取消这个请求。

  3. 内部数据

    • 自请求者传来的数据(这不是一个基于模块的层)。

  4. 映射

    • 按映射配置(出站响应数据的映射)指定的格式将数据转化为远程系统的格式。

    • 已经转化的数据返回给请求者。

  5. 外部数据

    • 转化后的数据准备发送给远程系统。

  6. 网络传输

    • 从请求者接收远程操作名称和已经转化为远程系统格式的数据。

    • 为网络传输构建一个有效的请求。

    • 将请求发送给远程系统并等待响应。

远程响应:
  1. 网络传输

    • 接收响应并解码数据的有效载荷。

    • 将数据返回给请求者。

  2. 外部数据

    • 从远程系统收到的数据。

  3. 映射

    • 数据已用这个操作的映射配置指定的映射(进入的响应数据映射)从外部系统格式转化为OTRS内部格式。

    • 已经转化的数据返回给请求者。

  4. 内部数据

    • 已经转化的数据返回给请求者。

  5. 调用程序

    • 接收返回的数据。

    • 根据每个调用程序的特殊需要处理数据(包括可能有的错误处理)。

    • 返回调用程序结果和数据到请求者。

  6. 事件处理程序或OTRS守护进程

    • 接收来自请求的数据。在使用OTRS守护进程的情况下,将来在数据中可能还包含了创建一个任务的信息。

Web服务

一个WEB服务是两个系统(在我们的例子中,就是OTRS和一个远程系统)间进行通讯的方法。

WEB服务的核心是它的配置,在配置中定义了WEB服务能够在内部执行什么操作(Operation操作)、OTRS请求能够在远程系统执行什么操作(Invokers调用程序),数据如何从一个系统转换到另外的系统(Mapping映射)以及通过什么协议进行通讯 (Transport传输)

通用接口是一个框架,使得在OTRS中能够用预定义的方法、使用已经构建的相互独立且可互换的块来创建WEB服务。

WEB服务图形界面

WEB服务图形界面是一个工具,允许你在用户友好、便捷的界面构建复杂的WEB服务配置。它允许:

  • 创建和删除WEB服务。

  • 导入和导出已有WEB服务的配置(用YAML文件格式)。

  • 在WEB服务历史屏幕查看、还原和导出已有WEB服务的老配置。

  • 在调试屏幕跟踪每个WEB服务所有的通讯日志。

WEB服务概览

在系统管理页面系统管理员部分的“WEB服务”链接通向WEB服务概览屏幕,你可以管理WEB服务的配置。你可以在这个屏幕中添加新的WEB服务或修改已有WEB服务的配置。

每个WEB服务配置屏幕的上部分有一行‘面包条’风格的导航路径,通过这个导航路径可以知道我们在WEB服务配置中的准确位置,还可以让用户随时跳回到配置流程的任何位置(这个跳回操作不会保存任何修改内容)。

注意

要创建一个新的WEB服务,点击“添加WEB服务”按钮,并输入需要的信息。

图 4.113. WEB服务概览

WEB服务概览


添加WEB服务

这部分必填的字段只有WEB服务的“名称”,要求系统唯一且不得留空。其它字段也是配置需要的如“调试阈值”和“有效性”,但是这些字段已经有默认值了。

调试阈值”的默认值是“debug(调试)”,当配置为这个方式时所有的通讯日志都会记录到数据库中。每个随后的调试阈值都有更多的限制并会丢弃比当前阈值级别低的通讯日志。

调试阈值级别(从低到高)

  • Debug(调试)

  • Info(信息)

  • Notice(注意)

  • Error(错误)

还可以为“OTRS作为服务提供方”和“OTRS作为服务请求方”定义网络传输协议。

点击“保存”按钮来将新的WEB服务注册到数据库中,或点击“取消”按钮丢弃这个操作。现在可以返回到WEB服务概览屏幕。

如果你已经有一个YAML格式的WEB服务配置文件,你可以点击屏幕左侧的“导入WEB服务”按钮。导入WEB服务的更多信息请检查下一部分的“修改WEB服务”。

注意

要为一个WEB服务添加或修改更多细节,点击WEB服务概览屏幕中WEB服务的名称。

图 4.114. 添加WEB服务

添加WEB服务


导入WEB服务样例

OTRS Business Solution™(OTRS商业解决方案)中有可用的示例Web服务,你知道吗?

修改WEB服务

在这个屏幕你有处理一个WEB服务所有部分的完整功能集。在左侧的操作栏中你可以找到一些按钮,允许你在一个WEB服务上执行所有可能的操作:

  • 克隆WEB服务。

  • 导出WEB服务。

  • 导入WEB服务。

  • 配置历史。

  • 删除WEB服务。

  • 调试器。

注意

配置历史”和“调试器”会打开不同的屏幕。

克隆WEB服务

要克隆一个WEB服务,你需要点击“克隆WEB服务”按钮。在打开的对话框中你可以为这个克隆的WEB服务使用默认的名称或设置一个新名称。

注意

记住:WEB服务的名称必须是系统中唯一的。

点击“克隆”按钮来创建这个WEB服务的克隆或“取消”按钮关闭这个对话框。

图 4.115. 克隆WEB服务

克隆WEB服务


导出WEB服务

导出WEB服务”按钮让你转储当前WEB服务配件到一个YAML文件,下载并保存到你的文件系统中。这在你要从一个服务器迁移WEB服务到另外的服务器时特别有用,例如从测试环境到生产系统。

警告

所有存储在WEB服务配置中的密码都将以纯文本格式导出。

在点击“导出WEB服务”按钮后,你的浏览器会出现一个保存文件对话框,就像你在网页上点击了一个文件下载链接一样。

注意

不同操作系统中不同浏览器有它自己的保存对话框屏幕和风格。取决于浏览器和它的配置,可能不会显示对话框而是直接将文件保存到一个默认目录中。如有需要请检查你的浏览器文档以获取更多的特定说明。

图 4.116. 导出WEB服务

导出WEB服务


导入WEB服务

导入WEB服务功能必须使用一个有效的WEB服务配置的YAML文件。点击“导入WEB服务”按钮,浏览配置文件或在输入框中输入文件的完整路径。

点击“导入”按钮以从一个文件创建一个新的WEB服务或“取消”关闭这个对话框。

注意

WEB服务的名称会使用配置文件的文件名(例如文件是MyWebservice.yml,则WEB服务将命名为MyWebservice)。如果在系统中已经有一个与之同名的WEB服务,系统会打开修改WEB服务屏幕,让你修改导入的WEB服务的名称。

图 4.117. 导入WEB服务

导入WEB服务


WEB服务历史

对WEB服务配置所做的每个修改都会在WEB服务历史中创建一条新条目(就像一个日志)。WEB服务历史屏幕显示一个WEB服务配置所有版本的列表。在“配置历史列表”中的每一行(每个版本)代表WEB服务历史中一个单独的修订。

点击一行可以显示在特定日期/时间的整个配置,这个配置会显示在本屏幕的“历史详细信息”部分。你还可以在这里导出选定的WEB服务配置版本或者恢复这个版本到当前的WEB服务配置。

导出Web服务配置的行为与Web服务更改屏幕中的“导出Web服务”功能完全相同。 有关更多信息,请参阅该部分。

如果对当前WEB服务配置的修改没有按预期工作,可以手动轻易恢复修改内容到原状,你可以点击“恢复WEB服务配置”按钮。这会打开一个对话框问你是否确定恢复到这个WEB服务配置。点击对话框中的“恢复WEB服务配置”按钮用选定版本替换当前的配置,或点击“取消”直接关闭对话框。

警告

记住:存储在WEB服务配置中的任何密码都将以纯文本格式导出。

恢复一个配置时请一定小心,因为这个过程是不可逆的。

图 4.118. WEB服务历史

WEB服务历史


删除WEB服务

有时需要完全删除一个WEB服务,如要这样做你可以点击“删除WEB服务”,会弹出一个确认对话框。

点击“删除”按钮来确认删除这个WEB服务或点击“取消”关闭此对话框。

警告

删除一个WEB服务后无法撤销,请在删除一个WEB服务时一定要小心。

图 4.119. 删除WEB服务

删除WEB服务


WEB服务调试器

调试器存储了一个WEB服务的日志。在调试器屏幕你可以跟踪该WEB服务作为提供者或请求者类型的所有通讯日志。

显示这个屏幕后,请求列表开始载入。在列表完全载入后你可以选择一行(即一条通讯序列)来检查它的详细信息,这个详细信息显示在屏幕下方。

你可以使用屏幕右边的过滤器来收缩通讯列表,你可以过滤的内容有:

  • 通讯类型(提供者或请求者)

  • 日期:在一个特定日期之前或之后

  • 远程IP地址

  • 以上所有组合

在设置了过滤器后,点击“刷新”按钮,就会显示满足搜索条件的新列表。

注意

取决于过滤器的搜索条件,新列表可能无返回结果。

在屏幕左侧的操作栏中你可以选择“返回WEB服务”,或点击“清除”按钮清空调试器日志,这会打开一个对话框确认清除日志,点击对话框中的“清除”按钮执行清除操作或点击“取消”关闭此对话框。

在“请求的详细信息”部分你可以看到选定通讯的所有详细信息。在这里你可以跟踪完整流并检查可能的错误或确认成功响应。

图 4.120. WEB服务调试器

WEB服务调试器


修改WEB服务配置

回到修改WEB服务屏幕,现在我们准备回顾屏幕右侧。在这里我们可以修改一个WEB服务的所有通用信息如名称、描述、调试阈值等等。此外下面还有两个部分允许我们修改通讯类型“OTRS作为提供方”和“OTRS作为请求方”的特定参数。

WEB服务配置需要在每个级别保存,这意味着如果修改了一个设置,到其它部分(这个配置更深层次的部分)的链接将被禁用,强迫你保存当前的配置级别。在保存后禁用了的链接会被重新启用,允许你使用这个配置继续。

在“OTRS作为提供方”部分可以设置或配置网络传输协议,只有注册了的网络传输后端才会显示在列表中。要配置网络传输,点击“配置”按钮。在这部分还可以添加新操作,从“添加操作”列表中选择一个可用的操作,这会引领你到操作配置屏幕。在保存了这个新操作后它就会在上面的表格里列出。

在“OTRS作为请求者”部分与前面非常类似,但你可以在这里添加调用程序而不是“操作”。

点击“保存”按钮以保存并继续配置这个WEB服务,“保存并完成”以保存并返回到WEB服务概览屏幕,或者“取消”以丢弃当前配置级别的修改内容并返回到WEB服务概览屏幕。

图 4.121. 修改WEB服务

修改WEB服务


注意

如同其它的通用接口配置屏幕(如网络传输、操作、调用程序和映射屏幕)一样,初始化配置(添加)屏幕仅提供了两个选项“保存”和“取消”。如果是重新查看这个配置,会出现新的选项“保存并完成”。这个功能的行为定义如下。

保存”将存储当前配置级别到数据库,并且会返回到之前的屏幕以查看修改内容,或配置更深的设置。

保存并完成”将存储当前配置级别到数据库,并且会返回到配置层次之前的屏幕(到上一个配置级别)。

取消”将丢弃当前配置级别的任何配置修改内容,并且会返回到配置层次之前的屏幕(到上一个配置级别)。

WEB服务提供都网络传输

将来可用的网络传输列表可能会增加,目前只有“HTTP::SOAP”和“HTTP::REST”传输可用。每个传输有不同的配置选项,并且可能使用不同的前端界面来配置它们。

配置“HTTP::SOAP”作为提供者很简单。只有两个设置“命名空间”和“消息的最大长度”。这些字段是必填的,第一个是一个URI(统一资源标识符),为SOAP方法指定一个上下文,减少歧义;第二个是你可以指定OTRS能够处理SOAP消息的最大尺寸(单位:字节)。

图 4.122. WEB服务提供者网络传输(HTTP::SOAP)

WEB服务提供者网络传输(HTTP::SOAP)


或者,你可能需要定义附加的响应头,它们可用于为每个响应添加静态标头值。 只需点击“添加响应头”并填充键和值字段。 附加的标头行的数量没有限制。

对于“HTTP::REST”,配置可能要稍微复杂一些,因为它的设置会根据配置的操作而动态增长,给每个操作添加两个设置:操作 ‘<操作名称>的路由映射’:操作 ‘<操作名称> 的有效请求方法':到默认的传输设置“消息的最大长度:”和“发送Keep-Alive(保持连接):”之前。

  • 路由映射,用于操作 ‘<操作名称>’:

    在这个设置中设置一个资源路径,这个路径必须根据WEB服务考虑的需求来定义,这个路径与HTTP请求方法相结合来确定要执行的通用接口操作。

    路径中可以包含变量,格式为‘:<VariableName>’。在变量位置的每个路径字符串会用这个设置中定义的变量名称替换后添加到请求的有效载荷中。

    例子:

    路由映射:/Resource

    • 有效的请求:

      http://localhost/otrs/nph-genericinterface.pl/Webservice/Test/Resource

      http://localhost/otrs/nph-genericinterface.pl/Webservice/Test/Resource?Param1=One

    • 无效的请求:

      http://localhost/otrs/nph-genericinterface.pl/Webservice/Test/Resource/

      http://localhost/otrs/nph-genericinterface.pl/Webservice/Test/Resource/OtherResource

      http://localhost/otrs/nph-genericinterface.pl/Webservice/Test/Resource/OtherResource?Param1=One

    路由映射:/Resource/:ID

    • 有效的请求:

      http://localhost/otrs/nph-genericinterface.pl/Webservice/Test/Resource/1

      http://localhost/otrs/nph-genericinterface.pl/Webservice/Test/Resource/1?Param1=One

      在这两种情况下,ID=1都会发送到操作作为有效载荷的一部分。在这2种情况还添加了Param1=One,取决于HTTP请求方法还会添加其它参数(如果它们在请求头字段中作为一个JSON字符串)。

    • 无效的请求:

      http://localhost/otrs/nph-genericinterface.pl/Webservice/Test/Resource

      http://localhost/otrs/nph-genericinterface.pl/Webservice/Test/Resource?Param1=One

    路由映射:/Resource/OtherResource/:ID/:Color

    • 有效的请求:

      http://localhost/otrs/nph-genericinterface.pl/Webservice/Test/Resource/OtherResource/1/Red

      http://localhost/otrs/nph-genericinterface.pl/Webservice/Test/Resource/OtherReosurce/123/Blue?Param1=One

      在第一个例子中,ID = 1且Color = Red,第二个例子中ID = 123且Color = Blue。

    • 无效的请求:

      http://localhost/otrs/nph-genericinterface.pl/Webservice/Test/Resource/1

      http://localhost/otrs/nph-genericinterface.pl/Webservice/Test/Resource/OtherResource/1

      http://localhost/otrs/nph-genericinterface.pl/Webservice/Test/Resource/OtherResource/1?Param1=One

      在第一个例子中,路径缺失了'/OtherResource'和:Color变量,在第二个例子中只缺失了:Color变量。

  • 有效的请求方法,用于操作‘<操作名称>’:

    HTTP请求方法结合路由映射来确定要使用的操作,可能的选项有:CONNECT、DELETE、GET、HEAD、OPTIONS、PATCH、POST、PUT和TRACE。

    完全不同的操作可以共享完全相同的映射路径,但是为了正确地确定使用的操作,每个操作的请求方法必须是唯一的。

图 4.123. WEB服务提供者网络传输(HTTP::REST)

WEB服务提供者网络传输(HTTP::REST)


WEB服务操作

当你使用OTRS作为一个WEB服务提供者时可以完执行的动作叫“操作”。每个操作属于一个控制器。控制器是操作或调用程序的集合,一般地,同一控制器中的操作需要类似的设置并共享相同的配置对话框,但是如果需要每个操作可以有独立的配置对话框。

一般出现在操作中的字段是Name(名称)Description(描述)Backend(后端)Mappings(映射),其它特殊字段可以出现在非默认配置对话框中以达到操作的特殊需要。

每个操作一般有两个映射配置部分,一个是进入数据映射,另外一个是出站数据映射。你可以为每个映射方向选择不同的映射类型(后端),因为它们的配置是彼此独立的,并且操作后端也是独立的。通常和最普遍的做法是操作在这两种情况下(反向的配置)使用相同的映射类型。完整的映射配置在一个单独的屏幕(取决于映射类型)中完成。

操作后端是预先选择的,不能编辑。如果在WEB服务编辑屏幕选择了该操作你就会看到这个参数。这个字段仅用于提供信息。

在屏幕左侧的操作栏中你有这些选项:“返回到WEB服务”(丢弃上次保存后的所有修改内容)和“删除”。如果你点击了“删除”,会打开一个对话框问你是否要删除这个操作,点击“删除”按钮确认删除该操作和它的配置,或点击“取消”关闭此删除对话框。

图 4.124. WEB服务的操作

WEB服务的操作


WEB服务请求者网络传输

WEB服务请求者的网络传输配置类似于提供者的配置。对于请求者的“HTTP::SOAP”网络传输需要设置更多的字段。

除了“Endpoint(端点)”(远程系统上的WEB服务用来接受请求的URI)和“Namespace(命名空间)”是必填字段外,你还要指定:

  • SOAP消息的编码(如utf-8、latin1、iso-8859-1、cp1250等等)

  • SOAPAction 头:你可以使用这个来发送一个空的或填满的SOAPAction头。设置为“”则SOAP消息中的SOAPAction 头会是一个空的字符串,或者设置为“是”以发送Namespace#Action格式的SOAP操作并定义分隔符(通常.NET WEB服务是“/”,REST是“#”)。

  • 身份认证:设置身份认证机制,设置为“-”不使用任何身份认证,或从列表中选择一个身份认证后会出现相关的详细字段。

注意

目前只实现了BasicAuth(HTTP基本认证)机制。你可以根据远程系统配置决定是否要用它。如果要使用BasicAuth,你必须提供用户名和密码来访问远程系统。

警告

如果你提供了一个身份认证密码并且随后你导出这个WEB服务到一个YAML文件,这个密码会以明文字符串导出到YAML文件中。请知悉这一点并在需要时采取必要的预防措施。

图 4.125. WEB服务请求者的网络传输(HTTP::SOAP)

WEB服务请求者的网络传输(HTTP::SOAP)


至于HTTP::REST,这个配置也会根据配置的调用程序动态增长,给每个调用程序添加两个设置:“调用程序 ‘<调用程序名称>的控制器映射:”和“调用程序 ‘<调用程序名称>’的有效请求命令:”。身份认证和SSL选项类似于HTTP::SOAP。

  • 主机

    远程系统的主机名称或IP地址和端口号,如果没有端口号,默认使用80端口。

  • 控制器映射,用于调用程序<调用程序名称>:

    在这个设置中设置一个资源路径,这个路径必须根据远程WEB服务的需求来定义,并遵从它的规定。

    路径可以包含‘:<变量名称>’格式的变量,每个变量名称匹配(要发送的)当前数据将被对应的数据值替换。匹配的变量名称和值将从当前数据中移除。取决于HTTP请求命令,剩余的数据可以在请求正文中作为一个JSON字符串或在URI中作为查询参数发送。

    例子:

    当前数据:Var1 = One, Var2 = Two, Var3 = Three and Var4 = Four。

    控制器映射:/Resource

    • 替换后:

      /Resource

    • 剩余数据:

      Var1 = One, Var2 = Two, Var3 = Three and Var4 = Four

    控制器映射:/Resource/:Var1

    • 替换后:

      /Resource/One

    • 剩余数据:

      Var2 = Two, Var3 = Three and Var4 = Four

    控制器映射:/Resource/:Var1?Param1=:Var2&Var3=:Var3

    • 替换后:

      /Resource/One?Param1=Two&Var3=Three

    • 剩余数据:

      Var4 = Four

  • 有效的请求命令,用于调用程序 ‘<调用程序名称>’:

    这个字段确定使用的HTTP请求方法,可能的选项有:CONNECT、DELETE、GET、HEAD、OPTIONS、PATCH、POST、PUT和TRACE。如果没有选择命令,则使用默认命令。

  • 默认命令

    用作所有没有定义请求命令的调用程序的最后依靠。

图 4.126. WEB服务请求者网络传输(HTTP::REST)

WEB服务请求者网络传输(HTTP::REST)


WEB服务调用程序

当你使用OTRS作为一个WEB服务请求者时能够执行的操作称之为调用程序。每个调用程序属于一个控制器(控制器是操作或调用程序的集合)。通常在相同控制器中的调用程序需要类似的设置和共同相同的配置对话框。每个调用程序如果需要可以有独立的配置对话框。

一般出现在每个调用程序中的字段是Name(名称)Description(描述)Backend(后端)Mappings(映射),其它特殊字段可以出现在非默认配置对话框中以达到调用程序的特殊需要。

每个调用程序通常有两个映射配置部分,一个是对进入的数据,另外一个是对发出的数据。你可以给每个映射方向选择不同的映射类型(后端),因为它们的配置是彼此独立的,调用程序后端也是独立的。通常和最普遍的做法是调用程序在这两种情况下(反射的配置)使用相同的映射类型。完整的映射配置在一个单独的屏幕(取决于映射类型)中完成。

操作后端是预先选择的,不能编辑。如果在WEB服务编辑屏幕选择了该调用程序你就会看到这个参数。这个字段仅用于提供信息。

事件触发器是OTRS中的事件,如TicketCreate(创建工单)ArticleSend(发送信件)等。它们可以作为执行调用程序的触发器。 每个调用程序需要至少注册一个事件触发器,否则调用程序将无用,因为它永远不会被调用。 另外,可以定义每个事件的一组规则(条件)以更好地控制事件的触发。这些规则取决于与事件相关联的对象数据。 事件触发器的异步属性定义是由OTRS进程处理调用程序,还是将调用程序委托给OTRS守护进程。

注意

OTRS守护进程是一个执行后台任务的单独的进程集,使用守护进程就不会影响OTRS进程本身,比如服务不可用或有网络问题,远程系统花费大量时间才响应。如果你不使用OTRS守护进程,则使用WEB服务会导致OTRS变慢或无法响应。所以强烈推荐尽可能使用异步事件触发器。

要添加一个事件触发器,首先从第一个列表中选择事件家族,然后从第二个列表中选择事件名称,然后设置异步属性(未选中即意味着事件触发器不是异步的),最后点击“+”按钮。就会创建一个新的事件触发器,会在调用程序的事件触发器列表中列出。

事件触发器列表中,每个事件显示是否包含条件。 条件属性旁边的编辑按钮允许添加或编辑事件的当前条件。

要删除一个事件触发器,简单定位到“事件触发器”列表中要删除的事件触发器,点击行尾的垃圾桶图标即可。这会打开一个对话框问你是否确认删除该事件触发器,点击删除从列表中删除这个事件触发器,或取消关闭此对话框。

在屏幕左侧操作栏你有两个选项:返回到WEB服务(丢失上次保存以来的所有修改内容)和“删除”。如果你点击了“删除”按钮,会弹出一个对话框问你是否要删除这个调用程序,点击删除按钮删除这个调用程序和它的配置,或取消关闭此删除对话框。

图 4.127. WEB服务调用程序

WEB服务调用程序


WEB服务调用程序事件

有时定义一个事件来触发一个调用程序可能会导致对远程服务器的许多不必要或错误的请求。 在这种情况下,可以设置事件条件来限制调用程序的触发。

要访问可以定义条件的事件设置屏幕,需要在调用程序屏幕中,并从中点击此条件生效的事件条件状态旁边的编辑图标。

在操作栏的事件设置屏幕中,有一个按钮返回到调用者屏幕以及一个按钮来删除所有事件条件。 默认情况下,屏幕预先填充第一个条件。 如果计划了多个条件,则更新条件之间的链接类型;如果一个条件内计划了多个字段,则从条件1开始更改字段之间的链接类型。 两个链接类型字段的都接受and(与)or(或)xor(异或)

填写字段名称,设置匹配类型(String是完全匹配,Regexp是正则表达式,或验证模块),并设置要匹配的值(在使用验证模块时需要完整的类名称如:Kernel::GenericInterface::Event::Validation::ValidateDemo)。

要向条件添加更多字段,请单击字段标题中的+按钮。 要删除字段,请单击字段行中的 - 按钮。 每个条件必须至少保留一个字段。

要添加更多条件,请点击最后一个条件框下面的按钮。 要删除某个条件,请单击条件标题中的 - 按钮。 集合中需要保留至少一个条件。 要删除所有条件,请使用侧边栏中的按钮。

图 4.128. WEB服务调用程序事件

WEB服务调用程序事件


WEB服务映射

有这种情况:你需要将一种格式的数据转化为另外的格式(映射或修改数据结构),因为通常一个WEB服务用来与一个远程系统交互,很可能不是另外一个OTRS系统并且/或者不能理解OTRS数据结构和值。在这些情况下一些或所有值必须被修改,有些时候甚至值的名称(键)或整个结构都需要修改,才能匹配另外一端期望的数据。

每个远程系统都有它自己的数据结构,可以为每种情况创建新的映射模块(例如:OTRS自带有一个为SAP Solution Manager定制的映射模块),但并不总是需要这样单独定制,Mapping::Simple模块可以涵盖大部分的映射需求。

注意

Mapping::Simple无法处理一个WEB服务所有的映射需求时,就需要创建一个映射模块。要学习关于如何创建一个新的映射模块的更多内容,请参阅OTRS开发手册。

这个模块让你有机会设置默认值来映射整个通讯数据中的每个键或值。

在屏幕的开始部分你会看到一个通用部分,在这里你可以设置默认规则,适用于所有没有映射的键和值。还有3个选项可用,如下列表:

  • 保持(保持不变):不对键或值做任何改动。

  • 忽略(丢弃键/值对):当这个选项用于键时它会删除键和值,因为当一个键被删除时结果就是键相关的值也被删除。当这个选项用于值时,只有这个值被删除,保留键(现在会关联一个空值)。

  • 映射到(使用提供键或值为默认):所有没有定义映射规则的键和/或值,使用这个映射作为默认映射,当你选择这个选项后会出现一个新的文本字段,用来设置默认键或值。

点击 + 按钮来添加新的键映射,会显示一个新框用于一个特定映射配置。你可以根据需要的随意添加键映射。只需再次点击 + 按钮,在已有映射的下面会出现一个新的映射框。从这个映射你可以定义一个特定键的映射,有下列选项:

  • 准确值:如果原键完全匹配,原键字符串会变为一个新的键。

  • 正则表达式:键字符串会按照一个正则表达式规则进行替换。

点击新增值映射的 + 按钮,会显示一个新行用于值映射。在这里也有键映射那样的选项(准确值和正则表达式)来定义每个值映射。你可以根据需要随意添加值映射,如果你要删除一个值映射,只需点击每个值映射行后面的 - 按钮即可。

可以删除完整的键映射部分(框),只需点击要删除的键映射框右上角的 - 按钮即可。

如果你要删除一个完整的映射配置,返回到相应的操作或调用程序屏幕,找到之前选择的映射方向并设置其值为 - ,然后保存配置即可。

图 4.129. WEB服务映射

WEB服务映射


WEB服务命令行接口

bin/otrs.Console.pl Admin::WebService::*系列命令被设计为一组基本但快速、强大的的工具以处理WEB服务配置。它们让你能够执行下列操作:

  • Add(添加):使用一个YAML文件作为配置源来创建WEB服务。

  • Update(更新):修改一个已有的WEB服务,使用一个不同的或修改过的YAML文件来修改WEB服务的配置。

  • Dump(转储):将当前的WEB服务的配置保存到一个文件。

  • List(列表):获取当前系统中注册的所有WEB服务的完整清单。

  • Delete(删除):从系统中删除一个WEB服务。使用它的时候要小心,因为这个操作无法复原。

例子:创建一个新的WEB服务配置:

shell> bin/otrs.Console.pl Admin::WebService::Add --name <webservice_name> --source-path /path/to/yaml/file
        

WEB服务配置

从WEB服务的设计来说,它主要考虑从一个OTRS系统到另外一个OTRS系统的可移植性,例如从一个测试或开发环境移植到生产系统。所以需要有一种容易的方式来从数据库提取WEB服务配置,并将它导入到另外一个系统。为完成这个任务,通用接口使用YAML文件作为WEB服务的配置基础。

为什么是YAML?YAML是一种标记语言,设计为人类友好的读和写(它比JSON更容易理解)。它没有XML的一些限制如数字标签,它是开放的和标准化的,并且完全足够用来存储整个WEB服务配置。

注意

要学习关于YAML的更多内容,请访问http://www.yaml.org/

下面是一个YAML格式的WEB服务配置文件例子:

---
Debugger:
  DebugThreshold: debug
Description: This an example of a web service configuration
Provider:
  Operation:
    CloseIncident:
      Description: This is a test operation
      MappingInbound: {}
      MappingOutbound: {}
      RemoteSystemGuid: ''
      Type: Test::Test
    Test:
      Description: This is a test operation
      MappingInbound:
        Config:
          KeyMapDefault:
            MapTo: ''
            MapType: Keep
          KeyMapExact:
            Prio: Priority
          ValueMap:
            Priority:
              ValueMapExact:
                Critical: 5 Very High
                Information: 1 Very Low
                Warning: 3 Normal
          ValueMapDefault:
            MapTo: 3 Normal
            MapType: MapTo
        Type: Simple
      MappingOutbound:
        Config:
          KeyMapDefault:
            MapTo: ''
            MapType: Ignore
          KeyMapExact:
            Priority: Prio
          ValueMap:
            Prio:
              ValueMapExact:
                1 Very Low: Information
                3 Normal: Warning
                5 Very High: Critical
          ValueMapDefault:
            MapTo: ''
            MapType: Ignore
        Type: Simple
      Type: Test::Test
  Transport:
    Config:
      MaxLength: 10000000
      NameSpace: http://www.example.com/actions
    Type: HTTP::SOAP
RemoteSystem: remote.system.description.example.com
Requester:
  Invoker:
    Test:
      Description: This is a test invoker
      Events:
        - Asynchronous: 1
        Condition:
          Condition:
            '1':
              Fields:
                Queue:
                  Match: Raw
                  Type: String
              Type: and
          ConditionLinking: and
          Event: TicketCreate
        - Asynchronous: 0
          Event: ArticleUpdate
      MappingInbound:
        Type: Simple
      MappingOutbound:
        Type: Simple
      Type: Test::Test
  Transport:
    Config:
      Authentication:
        Password: '*******'
        Type: BasicAuth
        User: otrs
      Encoding: utf-8
      Endpoint: http://www.example.com:8080/endpoint
      NameSpace: http://www.example.com/actions
      SOAPAction: Yes
      SOAPActionSeparator: '#'
    Type: HTTP::SOAP
            
        

配置详细信息

一般
  • Description(描述):描述WEB服务的简短文本。

  • RemoteSystem(远程系统):远程系统的简短描述。

  • Debugger(调试器):调试器设置的一个容器。

  • Provider(提供者):提供者设置的一个容器。

  • Requester(请求者):请求者设置的一个容器。

Debugger(调试器)
  • DebugThreshold(调试阈值):调试器的级别

    可能值

    • debug(调试):所有日志都存储到数据库。

    • info(信息):info(信息)、notice(注意)和error(错误)级别的日志存储到数据库。

    • notice(注意):notice(注意)和error(错误)级别的日志存储到数据库。

    • error(错误):只有error(错误)级别的日志存储到数据库。

Provider(提供者)
  • Operation(操作):有每个操作设置的一个容器。

  • Transport(传输):提供者网络传输设置的一个容器。

Operation(操作)
  • <OperationName操作名称>:操作的唯一名称,它自己的操作设置的容器(可以加基数0..n,但不能重复)。

<OperationName操作名称>

这部分基于来自Test::Test类型的操作,其它操作可能包含更多或不同的设置。

  • Description(描述):描述操作的简短文本。

  • MappingInbound(入站映射):进入的请求数据的映射设置容器。

  • MappingOutbound(出站映射):外发的响应数据的映射设置容器。

  • Type(类型):操作后端,格式为Controller::Operation。

MappingInbound(入站映射)

本部分内容基于映射类型Simple(简单),其它映射类型可能包含更多或不同的设置。

  • Config(配置):这个映射设置的容器。

  • Type(类型):映射后端。

Config(配置)
  • KeyMapDefault(默认的键映射):所有未映射的键的设置的容器。

  • ValueMapDefault(默认的值映射):所有未映射的值的设置的容器。

  • KeyMapExact(准确的键映射):所有准确的键映射(基数0 .. 1)的容器。

  • KeyMapRegEx(正则键映射):所有正则表达式的键映射(基数0 .. 1)的容器。

  • ValueMap(值映射):所有值映射(基数0 .. 1)的容器。

KeyMapDefault(默认的键映射)
  • MapTo(映射到):要使用的新值(只适用于映射类型设置为MapTo)。

  • MapType(映射类型):映射的规则。

    可能值

    • Keep(保持):保持不变。

    • Ignore(忽略): 丢弃。

    • MapTo(映射到):修改为MapTo的值。

ValueMapDefault(默认的值映射)

类似于KeyMapDefault(默认的键映射)

KeyMapExact(准确的键映射)
  • <oldkey原键>: <newkey新键>(基数 0 .. n,但不能重复)。

KeyMapRegEx(正则表达式键映射)
  • <oldkey原键>: <newkey新键>(基数 0 .. n,但不能重复)。

ValueMap(值映射)
  • <newkey(新键)>:这个新键的值映射容器(基数取决于来自KeyMapExactKeyMapRegEx的新键)。

<newkey新键>
  • ValueMapExact(准确的值映射):所有准确的值映射容器(基数 0 .. 1)。

  • KeyMapRegEx(正则表达式键映射):所有正则表达式的键映射(基数0 .. 1)的容器。

ValueMapExact(准确的值映射)
  • <oldvalue原值>: <newvalue新值> (基数 0 .. n,但不能重复)。

ValueMapRegEx(正则表达式值映射)
  • <oldvalue(RegEx)正则原值>: <newvalue新值> (基数 0 .. n,但不能重复)。

MappingOutbound(出站映射)

MappingInbound(入站映射)

Transport(传输)

本部分基于提供者的网络传输HTTP::SOAP,其它的传输可能包含更多或不同的设置。

  • Config(配置):这个特定的网络传输配置的容器。

  • Type(类型):提供者网络传输后端。

Config(配置)
  • MaxLength(最大长度):OTRS中一个SOAP消息能够读取的最大长度(单位:字节)。

  • NameSpace(命名空间):一个URI,给定一个属于这个WEB服务所有操作的上下文环境。

Requester(请求者)
  • Invoker(调用程序):每个调用程序的设置的容器。

  • Transport(传输):请求者网络传输设置的容器。

Invoker(调用程序)
  • <InvokerName调用程序名称>:该调用程序的唯一名称,它自己的调用程序设置的容器(基数 0 .. n,但不能重复)。

<InvokerName调用程序名称>

这部分基于来自Test::Test类型的调用程序,其它调用程序可能包含更多或不同的设置。

  • Description(描述):描述调用程序的简短文本。

  • Events(事件):事件触发器的未命名列表的容器。

  • MappingInbound(入站映射):进入的响应数据的映射设置的容器。

  • MappingOutbound(出站映射):外发的请求数据的映射设置容器。

  • Type(类型):调用程序后端,格式为Controller::Invoker

Events(事件)
  • 列表元素:(基数 0 .. n)。

    • Asynchronous(异步):设置是否委托给OTRS守护进程执行调用程序。

      可能值

      • 0:不由OTRS守护进程执行调用程序。

      • 1:由OTRS守护进程执行调用程序。

    • Condition(条件):触发调用程序的事件条件的容器,如果没有条件,事件总是会触发调用程序。

    • Event(事件):事件触发器的名称。

      可能的值(用于工单事件)

      • TicketCreate(创建工单)

      • TicketDelete(删除工单)

      • TicketTitleUpdate(工单标题更新)

      • TicketUnlockTimeoutUpdate(工单解锁超时更新)

      • TicketQueueUpdate(工单队列更新)

      • TicketTypeUpdate(工单类型更新)

      • TicketServiceUpdate(工单服务更新)

      • TicketSLAUpdate(工单SLA更新)

      • TicketCustomerUpdate(工单客户更新)

      • TicketPendingTimeUpdate(工单挂起时间更新)

      • TicketLockUpdate(工单锁定更新)

      • TicketArchiveFlagUpdate(工单归档标识更新)

      • TicketStateUpdate(工单状态更新)

      • TicketOwnerUpdate(工单所有者更新)

      • TicketResponsibleUpdate(工单负责人更新)

      • TicketPriorityUpdate(工单优先级更新)

      • HistoryAdd(添加历史)

      • HistoryDelete(删除历史)

      • TicketAccountTime(工单用时)

      • TicketMerge(工单合并)

      • TicketSubscribe(关注工单)

      • TicketUnsubscribe(取消关注工单)

      • TicketFlagSet(设置工单标识)

      • TicketFlagDelete(删除工单标识)

      • TicketSlaveLinkAdd(添加从工单链接)

      • TicketSlaveLinkDelete(删除从工单链接)

      • TicketMasterLinkDelete(删除主工单链接)

      可能的值(用于信件事件)

      • ArticleCreate(创建信件)

      • ArticleUpdate(更新信件)

      • ArticleSend(发送信件)

      • ArticleBounce(信件退回)

      • ArticleAgentNotification(服务人员通知信件)

      • ArticleCustomerNotification(客户通知信件)

      • ArticleAutoResponse(自动响应信件)

      • ArticleFlagSet(设置信件标识)

      • ArticleFlagDelete(删除信件标识)

Condition(条件)
  • Condition(条件):实际的事件条件的容器。

  • ConditionLinking(条件链接):定义多重条件如何相互影响。

    可能的值(用于条件链接)

    • and

    • or

    • xor

Condition -> Condition
  • <ConditionName(条件名称)>:条件元素的容器。

<ConditionName>

调用程序和事件中的条件的唯一名称,图形用户界面从1开始分配连续的整数作为条件名称。

  • Fields(字段):字段条件的容器。

  • Type(类型):定义一个条件下的多个字段如何交互。

    可能的值(用于条件链接)

    • and

    • or

    • xor

Fields(字段)
  • <FieldName(字段名称)>:字段属性的容器。

<FieldName>

来自事件对象的字段的名称,例如:对于工单事件,字段可以是Queue(队列)Priority(优先级)Type(类型)等。

  • Match(匹配):使用Type (类型)修饰符从所选的对象与事件对象匹配的值。

  • Type(类型):到Match(匹配)值的修饰符。

    可能的值(用于类型修饰符)

    • String(字符串):直接比较对象字段的值和Match(匹配)值。

    • Regexp(正则表达式):将对象字段的值与Match(匹配)值定义的正则表达式进行比较。

    • Module(模块):使用Match(匹配)中定义的模块比较对象数据。

MappingInbound(入站映射)

Operation(操作)MappingInbound(入站映射)

MappingOutbound(出站映射)

Operation(操作)MappingInbound(入站映射)

Transport(传输)

本部分基于请求者的网络传输HTTP::SOAP,其它的传输可能包含更多或不同的设置。

  • Config(配置):这个特定的网络传输配置的容器。

  • Type(类型):请求者网络传输后端。

Config(配置)
  • Authentication(身份认证):身份认证设置的容器。

  • Encoding(编码):SOAP消息请求的编码。

  • Endpoint(端点):远程服务器WEB服务的URI,用来接受OTRS的请求。

  • NameSpace(命名空间):一个URI,给定一个属于这个WEB服务所有调用程序的上下文环境。

  • SOAPAction:在SOAP消息中发送一个空的或填充的SOAPAction头(用<NameSpace> <Separator> <Action>格式)。

    可能值

    • Yes(是):发送填充的SOAPAction头。

    • No(否):发送一个空的SOAPAction头。

  • SOAPActionSeparator(SOAP操作分隔符):设置填满的SOAPAction头的<分隔符>

    可能值

    • '/':用于.NET WEB服务。

    • '#':用于所有的REST WEB服务。

Authentication(身份认证)
  • User(用户名):有权访问远程WEB服务的用户名。

  • Password(密码):特权用户的纯文本密码。

  • Type(类型):身份认证的类型。

连接器

连接器本质上是动作(在OTRS作为WEB服务提供者时叫操作,在OTRS作为WEB服务请求者时啊调用程序)的集合。但是它也可以包含特殊的映射或传输。

一个连接器可以只有操作、只有调用程序或者两者都有。一个连接器甚至可以使用其它连接器的一部分如映射或传输(如果它们不是部署为特定的连接器的话)。

换句话说,连接器不局限于控制器层,在需要时还能扩展到数据映射或网络传输层。

由于通用接口的模块化设计,连接器可以看作是一个插件;这意味着通过添加连接器,通用接口的能力可以扩展使用在:OTRS功能插件、OTRS定制模块、第三方模块等等。

捆绑的连接器

在当前版本的OTRS中有下列连接器可以使用:

  • 会话

  • 工单

会话连接器

这个连接器可以创建一个有效的会话ID,能够用在其它任何操作中。

提供:

  • 操作:

    • SessionCreate(创建会话)

    • SessionGet(获取会话)

操作
SessionCreate(创建会话)

创建一个新的有效会话ID,用在其它连接器比如创建工单的其它操作中。

注意

要在其它连接器的其它操作中使用这个会话ID,需要该操作通过会话ID部署身份认证。所有剩下的捆绑操作都有能力接受一个有效的会话ID作为一个身份认证方法。

可能的属性:

                            
      <SessionCreate>
         <!--You have a MANDATORY CHOICE of the next 2 items at this level-->
         <!--Optional:-->
         <UserLogin>?</UserLogin>
         <!--Optional:-->
         <CustomerUserLogin>?</CustomerUserLogin>
         <!--Optional:-->
         <Password>?</Password>
      </SessionCreate>
                            
                        

SessionCreate(创建会话)

从一个有效的会话搜集数据,不包括用户密码或质疑令牌等敏感信息。

注意

如果它的任何值是一个复杂的结构,那么它将自动转换为一个JSON字符串。

可能的属性:

                            
      <SessionGet>
         <SessionID>?</SessionID>
      </SessionGet>
                            
                        

工单连接器

这个连接器提供与工单交互的基本功能。

提供:

  • 操作:

    • 工单创建

    • TicketUpdate(更新工单)

    • TicketGet(获取工单)

    • TicketSearch(搜索工单)

    • TicketHistoryGet(获取工单历史)

操作
工单创建

提供一个接口以在OTRS中创建一个工单。一个工单必须包含一个信件并包含数个附件,所有定义的动态字段也可以在创建工单操作时设置。

可能的属性:

                            
      <TicketCreate>
         <!--You have a MANDATORY CHOICE of the next 3 items at this level-->
         <!--Optional:-->
         <UserLogin>?</UserLogin>
         <!--Optional:-->
         <CustomerUserLogin>?</CustomerUserLogin>
         <!--Optional:-->
         <SessionID>?</SessionID>
         <!--Optional:-->
         <Password>?</Password>
         <Ticket>
            <Title>?</Title>
            <!--You have a MANDATORY CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <QueueID>?</QueueID>
            <!--Optional:-->
            <Queue>?</Queue>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <TypeID>?</TypeID>
            <!--Optional:-->
            <Type>?</Type>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <ServiceID>?</ServiceID>
            <!--Optional:-->
            <Service>?</Service>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <SLAID>?</SLAID>
            <!--Optional:-->
            <SLA>?</SLA>
            <!--You have a MANDATORY CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <StateID>?</StateID>
            <!--Optional:-->
            <State>?</State>
            <!--You have a MANDATORY CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <PriorityID>?</PriorityID>
            <!--Optional:-->
            <Priority>?</Priority>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <OwnerID>?</OwnerID>
            <!--Optional:-->
            <Owner>?</Owner>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <ResponsibleID>?</ResponsibleID>
            <!--Optional:-->
            <Responsible>?</Responsible>
            <CustomerUser>?</CustomerUser>
            <!--Optional:-->
            <CustomerID>?</CustomerID>
            <!--Optional:-->
            <PendingTime>
               <!--You have a CHOICE of the next and the other 5 items at this level-->
               <Diff>?</Diff>
               <Year>?</Year>
               <Month>?</Month>
               <Day>?</Day>
               <Hour>?</Hour>
               <Minute>?</Minute>
            </PendingTime>
         </Ticket>
         <Article>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <CommunicationChannelID>?</CommunicationChannelID>
            <!--Optional: Possible values Email, Internal or Phone-->
            <CommunicationChannel>?</CommunicationChannel>
            <IsVisibleForCustomer>?</IsVisibleForCustomer>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <SenderTypeID>?</SenderTypeID>
            <!--Optional:-->
            <SenderType>?</SenderType>
            <!--Optional:-->
            <From>?</From>
            <Subject>?</Subject>
            <Body>?</Body>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <ContentType>?</ContentType>
            <Charset>?</Charset>
            <MimeType>?</MimeType>
            <!--Optional:-->
            <HistoryType>?</HistoryType>
            <!--Optional:-->
            <HistoryComment>?</HistoryComment>
            <!--Optional:-->
            <AutoResponseType>?</AutoResponseType>
            <!--Optional:-->
            <TimeUnit>?</TimeUnit>
            <!--Optional:-->
            <NoAgentNotify>?</NoAgentNotify>
            <!--Zero or more repetitions:-->
            <ForceNotificationToUserID>?</ForceNotificationToUserID>
            <!--Zero or more repetitions:-->
            <ExcludeNotificationToUserID>?</ExcludeNotificationToUserID>
            <!--Zero or more repetitions:-->
            <ExcludeMuteNotificationToUserID>?</ExcludeMuteNotificationToUserID>
         </Article>
         <!--Zero or more repetitions:-->
         <DynamicField>
            <Name>?</Name>
            <!--1 or more repetitions:-->
            <Value>?</Value>
         </DynamicField>
         <!--Zero or more repetitions:-->
         <Attachment>
            <Content>cid:61886944659</Content>
            <ContentType>?</ContentType>
            <Filename>?</Filename>
         </Attachment>
      </TicketCreate>
                            
                        

TicketUpdate(更新工单)

‘更新工单’操作用来修改已有工单的属性或者添加一个新的信件(包括附件和所有定义的工单和信件的动态字段)。

注意

没有必要创建一个信件来修改一个工单的属性。

可能的属性:

                            
      <TicketUpdate>
         <!--You have a MANDATORY CHOICE of the next 3 items at this level-->
         <!--Optional:-->
         <UserLogin>?</UserLogin>
         <!--Optional:-->
         <CustomerUserLogin>?</CustomerUserLogin>
         <!--Optional:-->
         <SessionID>?</SessionID>
         <!--Optional:-->
         <Password>?</Password>
         <!--You have a CHOICE of the next 2 items at this level-->
         <TicketID>?</TicketID>
         <TicketNumber>?</TicketNumber>
         <!--Optional:-->
         <Ticket>
            <!--Optional:-->
            <Title>?</Title>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <QueueID>?</QueueID>
            <!--Optional:-->
            <Queue>?</Queue>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <TypeID>?</TypeID>
            <!--Optional:-->
            <Type>?</Type>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <ServiceID>?</ServiceID>
            <!--Optional:-->
            <Service>?</Service>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <SLAID>?</SLAID>
            <!--Optional:-->
            <SLA>?</SLA>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <StateID>?</StateID>
            <!--Optional:-->
            <State>?</State>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <PriorityID>?</PriorityID>
            <!--Optional:-->
            <Priority>?</Priority>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <OwnerID>?</OwnerID>
            <!--Optional:-->
            <Owner>?</Owner>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <ResponsibleID>?</ResponsibleID>
            <!--Optional:-->
            <Responsible>?</Responsible>
            <!--Optional:-->
            <CustomerUser>?</CustomerUser>
            <!--Optional:-->
            <CustomerID>?</CustomerID>
            <!--Optional:-->
            <PendingTime>
               <!--You have a CHOICE of the next and the other 5 items at this level-->
               <Diff>?</Diff>
               <Year>?</Year>
               <Month>?</Month>
               <Day>?</Day>
               <Hour>?</Hour>
               <Minute>?</Minute>
            </PendingTime>
         </Ticket>
         <!--Optional:-->
         <Article>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <CommunicationChannelID>?</CommunicationChannelID>
            <!--Optional: Possible values Email, Internal or Phone-->
            <CommunicationChannel>?</CommunicationChannel>
            <IsVisibleForCustomer>?</IsVisibleForCustomer>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <SenderTypeID>?</SenderTypeID>
            <!--Optional:-->
            <SenderType>?</SenderType>
            <!--Optional:-->
            <From>?</From>
            <Subject>?</Subject>
            <Body>?</Body>
            <!--You have a CHOICE of the next 2 items at this level-->
            <!--Optional:-->
            <ContentType>?</ContentType>
            <Charset>?</Charset>
            <MimeType>?</MimeType>
            <!--Optional:-->
            <HistoryType>?</HistoryType>
            <!--Optional:-->
            <HistoryComment>?</HistoryComment>
            <!--Optional:-->
            <AutoResponseType>?</AutoResponseType>
            <!--Optional:-->
            <TimeUnit>?</TimeUnit>
            <!--Optional:-->
            <NoAgentNotify>?</NoAgentNotify>
            <!--Zero or more repetitions:-->
            <ForceNotificationToUserID>?</ForceNotificationToUserID>
            <!--Zero or more repetitions:-->
            <ExcludeNotificationToUserID>?</ExcludeNotificationToUserID>
            <!--Zero or more repetitions:-->
            <ExcludeMuteNotificationToUserID>?</ExcludeMuteNotificationToUserID>
         </Article>
         <!--Zero or more repetitions:-->
         <DynamicField>
            <Name>?</Name>
            <!--1 or more repetitions:-->
            <Value>?</Value>
         </DynamicField>
         <!--Zero or more repetitions:-->
         <Attachment>
            <Content>cid:166861569966</Content>
            <ContentType>?</ContentType>
            <Filename>?</Filename>
         </Attachment>
      </TicketUpdate>
                            
                        

TicketGet(获取工单)

这个操作用来获取一个工单的所有属性,包括动态字段、所有信件和属于工单的所有附件。

可能的属性:

                            
      <TicketGet>
         <!--You have a MANDATORY CHOICE of the next 3 items at this level-->
         <!--Optional:-->
         <UserLogin>?</UserLogin>
         <!--Optional:-->
         <CustomerUserLogin>?</CustomerUserLogin>
         <!--Optional:-->
         <SessionID>?</SessionID>
         <!--Optional:-->
         <Password>?</Password>
         <!--1 or more repetitions:-->
         <TicketID>?</TicketID>
         <!--Optional:-->
         <DynamicFields>?</DynamicFields>
         <!--Optional:-->
         <Extended>?</Extended>
         <!--Optional:-->
         <AllArticles>?</AllArticles>
         <!--Optional:-->
         <ArticleSenderType>?</ArticleSenderType>
         <!--Optional:-->
         <ArticleOrder>?</ArticleOrder>
         <!--Optional:-->
         <ArticleLimit>?</ArticleLimit>
         <!--Optional:-->
         <Attachments>?</Attachments>
         <!--Optional:-->
         <GetAttachmentContents>?</GetAttachmentContents>
         <!--Optional:-->
         <HTMLBodyAsAttachment>?</HTMLBodyAsAttachment>
      </TicketGet>
                            
                        

TicketSearch(搜索工单)

‘搜索工单’操作返回匹配一个预定义条件的工单编号列表。

可能的属性:

                            
      <TicketSearch>
         <!--You have a MANDATORY CHOICE of the next 3 items at this level-->
         <!--Optional:-->
         <UserLogin>?</UserLogin>
         <!--Optional:-->
         <CustomerUserLogin>?</CustomerUserLogin>
         <!--Optional:-->
         <SessionID>?</SessionID>
         <!--Optional:-->
         <Password>?</Password>
         <!--Optional:-->
         <Limit>?</Limit>
         <!--Zero or more repetitions:-->
         <TicketNumber>?</TicketNumber>
         <!--Zero or more repetitions:-->
         <Title>?</Title>
         <!--Zero or more repetitions:-->
         <Queues>?</Queues>
         <!--Zero or more repetitions:-->
         <QueueIDs>?</QueueIDs>
         <!--Optional:-->
         <UseSubQueues>?</UseSubQueues>
         <!--Zero or more repetitions:-->
         <Types>?</Types>
         <!--Zero or more repetitions:-->
         <TypeIDs>?</TypeIDs>
         <!--Zero or more repetitions:-->
         <States>?</States>
         <!--Zero or more repetitions:-->
         <StateIDs>?</StateIDs>
         <!--Zero or more repetitions:-->
         <StateType>?</StateType>
         <!--Zero or more repetitions:-->
         <StateTypeIDs>?</StateTypeIDs>
         <!--Zero or more repetitions:-->
         <Priorities>?</Priorities>
         <!--Zero or more repetitions:-->
         <PriorityIDs>?</PriorityIDs>
         <!--Zero or more repetitions:-->
         <Services>?</Services>
         <!--Zero or more repetitions:-->
         <ServiceIDs>?</ServiceIDs>
         <!--Zero or more repetitions:-->
         <SLAs>?</SLAs>
         <!--Zero or more repetitions:-->
         <SLAIDs>?</SLAIDs>
         <!--Zero or more repetitions:-->
         <Locks>?</Locks>
         <!--Zero or more repetitions:-->
         <LockIDs>?</LockIDs>
         <!--Zero or more repetitions:-->
         <OwnerIDs>?</OwnerIDs>
         <!--Zero or more repetitions:-->
         <ResponsibleIDs>?</ResponsibleIDs>
         <!--Zero or more repetitions:-->
         <WatchUserIDs>?</WatchUserIDs>
         <!--Zero or more repetitions:-->
         <CustomerID>?</CustomerID>
         <!--Zero or more repetitions:-->
         <CustomerUserLogin>?</CustomerUserLogin>
         <!--Zero or more repetitions:-->
         <CreatedUserIDs>?</CreatedUserIDs>
         <!--Zero or more repetitions:-->
         <CreatedTypes>?</CreatedTypes>
         <!--Zero or more repetitions:-->
         <CreatedTypeIDs>?</CreatedTypeIDs>
         <!--Zero or more repetitions:-->
         <CreatedPriorities>?</CreatedPriorities>
         <!--Zero or more repetitions:-->
         <CreatedPriorityIDs>?</CreatedPriorityIDs>
         <!--Zero or more repetitions:-->
         <CreatedStates>?</CreatedStates>
         <!--Zero or more repetitions:-->
         <CreatedStateIDs>?</CreatedStateIDs>
         <!--Zero or more repetitions:-->
         <CreatedQueues>?</CreatedQueues>
         <!--Zero or more repetitions:-->
         <CreatedQueueIDs>?</CreatedQueueIDs>
         <!--Zero or more repetitions:-->
         <DynamicField>
            <Name>?<Name>
            <!--You have a MANDATORY CHOICE of the next 6 items at this level-->
            <!--Optional:-->
            <Equals>?</Equals>
            <!--Optional:-->
            <Like>?</Like>
            <!--Optional:-->
            <GreaterThan>?</GreaterThan>
            <!--Optional:-->
            <GreaterThanEquals>?</GreaterThanEquals>
            <!--Optional:-->
            <SmallerThan>?</SmallerThan>
            <!--Optional:-->
            <SmallerThanEquals>?</SmallerThanEquals>
         </DynamicField>
         <!--Optional:-->
         <Ticketflag>
            <!--Optional:-->
            <Seen>?</Seen>
         </Ticketflag>
         <!--Optional:-->
         <From>?</From>
         <!--Optional:-->
         <To>?</To>
         <!--Optional:-->
         <Cc>?</Cc>
         <!--Optional:-->
         <Subject>?</Subject>
         <!--Optional:-->
         <Body>?</Body>
         <!--Optional:-->
         <FullTextIndex>?</FullTextIndex>
         <!--Optional:-->
         <ContentSearch>?</ContentSearch>
         <!--Optional:-->
         <ConditionInline>?</ConditionInline>
         <!--Optional:-->
         <ArticleCreateTimeOlderMinutes>?</ArticleCreateTimeOlderMinutes>
         <!--Optional:-->
         <ArticleCreateTimeNewerMinutes>?</ArticleCreateTimeNewerMinutes>
         <!--Optional:-->
         <ArticleCreateTimeNewerDate>?</ArticleCreateTimeNewerDate>
         <!--Optional:-->
         <ArticleCreateTimeOlderDate>?</ArticleCreateTimeOlderDate>
         <!--Optional:-->
         <TicketCreateTimeOlderMinutes>?</TicketCreateTimeOlderMinutes>
         <!--Optional:-->
         <ATicketCreateTimeNewerMinutes>?</ATicketCreateTimeNewerMinutes>
         <!--Optional:-->
         <TicketCreateTimeNewerDate>?</TicketCreateTimeNewerDate>
         <!--Optional:-->
         <TicketCreateTimeOlderDate>?</TicketCreateTimeOlderDate>
         <!--Optional:-->
         <TicketLastChangeTimeOlderMinutes>?</TicketLastChangeTimeOlderMinutes>
         <!--Optional:-->
         <TicketLastChangeTimeNewerMinutes>?</TicketLastChangeTimeNewerMinutes>
         <!--Optional:-->
         <TicketLastChangeTimeNewerDate>?</TicketLastChangeTimeNewerDate>
         <!--Optional:-->
         <TicketLastChangeTimeOlderDate>?</TicketLastChangeTimeOlderDate>
         <!--Optional:-->
         <TicketChangeTimeOlderMinutes>?</TicketChangeTimeOlderMinutes>
         <!--Optional:-->
         <TicketChangeTimeNewerMinutes>?</TicketChangeTimeNewerMinutes>
         <!--Optional:-->
         <TicketChangeTimeNewerDate>?</TicketChangeTimeNewerDate>
         <!--Optional:-->
         <TicketChangeTimeOlderDate>?</TicketChangeTimeOlderDate>
         <!--Optional:-->
         <TicketCloseTimeOlderMinutes>?</TicketCloseTimeOlderMinutes>
         <!--Optional:-->
         <TicketCloseTimeNewerMinutes>?</TicketCloseTimeNewerMinutes>
         <!--Optional:-->
         <TicketCloseTimeNewerDate>?</TicketCloseTimeNewerDate>
         <!--Optional:-->
         <TicketCloseTimeOlderDate>?</TicketCloseTimeOlderDate>
         <!--Optional:-->
         <TicketPendingTimeOlderMinutes>?</TicketPendingTimeOlderMinutes>
         <!--Optional:-->
         <TicketPendingTimeNewerMinutes>?</TicketPendingTimeNewerMinutes>
         <!--Optional:-->
         <TicketPendingTimeNewerDate>?</TicketPendingTimeNewerDate>
         <!--Optional:-->
         <TicketPendingTimeOlderDate>?</TicketPendingTimeOlderDate>
         <!--Optional:-->
         <TicketEscalationTimeOlderMinutes>?</TicketEscalationTimeOlderMinutes>
         <!--Optional:-->
         <TTicketEscalationTimeNewerMinutes>?</TTicketEscalationTimeNewerMinutes>
         <!--Optional:-->
         <TicketEscalationTimeNewerDate>?</TicketEscalationTimeNewerDate>
         <!--Optional:-->
         <TicketEscalationTimeOlderDate>?</TicketEscalationTimeOlderDate>
         <!--Optional:-->
         <ArchiveFlags>?</ArchiveFlags>
         <!--Zero or more repetitions:-->
         <OrderBy>?</OrderBy>
         <!--Zero or more repetitions:-->
         <SortBy>?</SortBy>
         <!--Zero or more repetitions:-->
         <CustomerUserID>?</CustomerUserID>
      </TicketSearch>
                            
                        

TicketHistoryGet(获取工单历史)

这个操作用于从一个或多个工单中获取所有历史记录。

可能的属性:

                            
      <TicketHistoryGet>
         <!--You have a MANDATORY CHOICE of the next 2 items at this level-->
         <!--Optional:-->
         <UserLogin>?</UserLogin>
         <!--Optional:-->
         <SessionID>?</SessionID>
         <!--Optional:-->
         <Password>?</Password>
         <!--1 or more repetitions:-->
         <TicketID>?</TicketID>
      </TicketHistoryGet>
                            
                        

例子:

WEB服务配置

下面是一个基本但完整的YAML格式的WEB服务配置文件,通过SOAP网络传输方法使用了所有的工单连接器操作。为了在OTRS中使用它,你需要复制它的内容到一个叫GenericTicketConnectorSOAP.yml的文件,并且在系统管理页面进入WEB服务屏幕,然后在WEB服务概览屏幕点击“添加WEB服务”按钮,然后在添加WEB服务屏幕点击“导入WEB服务”按钮,将这个文件导入到OTRS中。

                    
---
Debugger:
  DebugThreshold: debug
  TestMode: 0
Description: Ticket Connector SOAP Sample
FrameworkVersion: 3.4.x git
Provider:
  Operation:
    SessionCreate:
      Description: Creates a Session
      MappingInbound: {}
      MappingOutbound: {}
      Type: Session::SessionCreate
    TicketCreate:
      Description: Creates a Ticket
      MappingInbound: {}
      MappingOutbound: {}
      Type: Ticket::TicketCreate
    TicketUpdate:
      Description: Updates a Ticket
      MappingInbound: {}
      MappingOutbound: {}
      Type: Ticket::TicketUpdate
    TicketGet:
      Description: Retrieves Ticket data
      MappingInbound: {}
      MappingOutbound: {}
      Type: Ticket::TicketGet
    TicketSearch:
      Description: Search for Tickets
      MappingInbound: {}
      MappingOutbound: {}
      Type: Ticket::TicketSearch
    TicketHistoryGet:
      Description: Retrieves history of a Ticket
      MappingInbound: {}
      MappingOutbound: {}
      Type: Ticket::TicketHistoryGet
  Transport:
    Config:
      MaxLength: 100000000
      NameSpace: http://www.otrs.org/TicketConnector/
    Type: HTTP::SOAP
RemoteSystem: ''
Requester:
  Transport:
    Type: ''
                    
                

类似的例子可以用REST网络传输做到,REST WEB服务使用HTTP操作比如“POST”、“GET”、“PUT”、“PATCH”等等。这个操作连同一个叫做资源的URI路径一起定义一个OTRS通用接口操作或调用程序(取决于通讯方式)。

下列的例子为‘创建会话’使用/Session资源,为搜索工单和创建工单使用 /Ticket资源,为获取工单和更新工单使用/Ticket/{TicketID}郑源(这里{TicketID}是一个工单的实际工单ID,例如/Ticket/123)。为了在OTRS中使用它,你需要复制它的内容到一个叫GenericTicketConnectorREST.yml的文件,并且在系统管理页面进入WEB服务屏幕,然后在WEB服务概览屏幕点击“添加WEB服务”按钮,然后在添加WEB服务屏幕点击“导入WEB服务”按钮,将这个文件导入到OTRS中。

                    
---
Debugger:
  DebugThreshold: debug
  TestMode: '0'
Description: Ticket Connector REST Sample
FrameworkVersion: 3.4.x git
Provider:
  Operation:
    SessionCreate:
      Description: Creates a Session
      MappingInbound: {}
      MappingOutbound: {}
      Type: Session::SessionCreate
    TicketCreate:
      Description: Creates a Ticket
      MappingInbound: {}
      MappingOutbound: {}
      Type: Ticket::TicketCreate
    TicketGet:
      Description: Retrieves Ticket data
      MappingInbound: {}
      MappingOutbound: {}
      Type: Ticket::TicketGet
    TicketSearch:
      Description: Search for Tickets
      MappingInbound: {}
      MappingOutbound: {}
      Type: Ticket::TicketSearch
    TicketUpdate:
      Description: Updates a Ticket
      MappingInbound: {}
      MappingOutbound: {}
      Type: Ticket::TicketUpdate
    TicketHistoryGet:
      Description: Retrieves history of a Ticket
      MappingInbound: {}
      MappingOutbound: {}
      Type: Ticket::TicketHistoryGet
  Transport:
    Config:
      KeepAlive: ''
      MaxLength: '100000000'
      RouteOperationMapping:
        SessionCreate:
          RequestMethod:
          - POST
          Route: /Session
        TicketCreate:
          RequestMethod:
          - POST
          Route: /Ticket
        TicketGet:
          RequestMethod:
          - GET
          Route: /Ticket/:TicketID
        TicketSearch:
          RequestMethod:
          - GET
          Route: /Ticket
        TicketUpdate:
          RequestMethod:
          - PATCH
          Route: /Ticket/:TicketID
        TicketHistoryGet:
          RequestMethod:
          - GET
          Route: /TicketHistory/:TicketID
    Type: HTTP::REST
RemoteSystem: ''
Requester:
  Transport:
    Type: ''
                    
                

Perl SOAP请求者

下列代码是一个Perl脚本,可以通过通用接口连接到OTRS。为了执行工单连接器提供的操作,它使用了两个Perl的CPAN模块:SOAP::Lite和Data::Dumper。在你尝试运行这个脚本之前,请确保你的环境能够使用这些模块。

                    
#!/usr/bin/perl -w
# --
# otrs.SOAPRequest.pl - sample to send a SOAP request to OTRS Generic Interface Ticket Connector
# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/
# --
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/gpl-3.0.txt.
# --

use strict;
use warnings;

# use ../ as lib location
use File::Basename;
use FindBin qw($RealBin);
use lib dirname($RealBin);

use SOAP::Lite;
use Data::Dumper;

# ---
# Variables to be defined.

# this is the URL for the web service
# the format is
# <HTTP_TYPE>:://<OTRS_FQDN>/nph-genericinterface.pl/Webservice/<WEB_SERVICE_NAME>
# or
# <HTTP_TYPE>:://<OTRS_FQDN>/nph-genericinterface.pl/WebserviceID/<WEB_SERVICE_ID>
my $URL = 'http://localhost/otrs/nph-genericinterface.pl/Webservice/GenericTicketConnector';

# this name space should match the specified name space in the SOAP transport for the web service.
my $NameSpace = 'http://www.otrs.org/TicketConnector/';

# this is operation to execute, it could be TicketCreate, TicketUpdate, TicketGet, TicketSearch
# or SessionCreate. and they must to be defined in the web service.
my $Operation = 'TicketCreate';

# this variable is used to store all the parameters to be included on a request in XML format. Each
# operation has a determined set of mandatory and non mandatory parameters to work correctly. Please
# check the OTRS Admin Manual in order to get a complete list of parameters.
my $XMLData = '
<UserLogin>some user login</UserLogin>
<Password>some password</Password>
<Ticket>
    <Title>some title</Title>
    <CustomerUser>some customer user login</CustomerUser>
    <Queue>some queue</Queue>
    <State>some state</State>
    <Priority>some priority</Priority>
</Ticket>
<Article>
    <Subject>some subject</Subject>
    <Body>some body</Body>
    <ContentType>text/plain; charset=utf8</ContentType>
</Article>
';

# ---

# create a SOAP::Lite data structure from the provided XML data structure.
my $SOAPData = SOAP::Data
    ->type( 'xml' => $XMLData );

my $SOAPObject = SOAP::Lite
    ->uri($NameSpace)
    ->proxy($URL)
    ->$Operation($SOAPData);

# check for a fault in the soap code.
if ( $SOAPObject->fault ) {
    print $SOAPObject->faultcode, " ", $SOAPObject->faultstring, "\n";
}

# otherwise print the results.
else {

    # get the XML response part from the SOAP message.
    my $XMLResponse = $SOAPObject->context()->transport()->proxy()->http_response()->content();

    # deserialize response (convert it into a perl structure).
    my $Deserialized = eval {
        SOAP::Deserializer->deserialize($XMLResponse);
    };

    # remove all the headers and other not needed parts of the SOAP message.
    my $Body = $Deserialized->body();

    # just output relevant data and no the operation name key (like TicketCreateResponse).
    for my $ResponseKey ( keys %{$Body} ) {
        print Dumper( $Body->{$ResponseKey} );
    }
}
                    
                

Perl REST请求者

下列的代码是一个Perl脚本,可以通过通用接口连接到OTRS。为了执行工单连接器提供的操作,它使用了三个Perl的CPAN模块:JSON、REST::Client和Data::Dumper。在你尝试运行这个脚本之前,请确保你的环境能够使用这些模块。

                    
#!/usr/bin/perl
# --
# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/
# --
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/gpl-3.0.txt.
# --

use strict;
use warnings;
use utf8;

## nofilter(TidyAll::Plugin::OTRS::Perl::Dumper)

# use ../ as lib location
use File::Basename;
use FindBin qw($RealBin);
use lib dirname($RealBin);

use JSON;
use REST::Client;

# This is the HOST for the web service the format is:
# <HTTP_TYPE>:://<OTRS_FQDN>/nph-genericinterface.pl
my $Host = 'http://localhost/otrs/nph-genericinterface.pl';

my $RestClient = REST::Client->new(
    {
        host => $Host,
    }
);

# These are the Controllers and Providers the format is:
# /Webservice/<WEB_SERVICE_NAME>/<RESOURCE>/<REQUEST_VALUE>
# or
# /WebserviceID/<WEB_SERVICE_ID>/<RESOURCE>/<REQUEST_VALUE>
#
# See the documentation on how to setup Providers.
#
# This example will retrieve the Ticket with the TicketID = 1 (<REQUEST_VALUE>)
my $GetControllerAndRequest = '/Webservice/GenericTicketConnectorREST/Ticket/1';

# This example is the base URL for Ticket Create
my $CreateControllerAndRequest = '/Webservice/GenericTicketConnectorREST/Ticket';

# This example will update the Ticket with the TicketID = 1 (<REQUEST_VALUE>)
my $UpdateControllerAndRequest = '/Webservice/GenericTicketConnectorREST/Ticket/1';

# This is the base URL for Ticket Search
my $SearchControllerAndRequest = '/Webservice/GenericTicketConnectorREST/Ticket';

# This is the base URL for Ticket history with the TicketID = 1 (<REQUEST_VALUE>)
my $HistoryControllerAndRequest = '/Webservice/GenericTicketConnectorREST/TicketHistory/1';

# TicketGet Example
# See the documentation of OTRSGenericInterfaceREST on how to setup
#   - webservice
#   - transport
#   - operations
my $GetParams = {
    UserLogin => "some agent user login",       # to be filled with valid agent login
    Password  => "some agent user password",    # to be filled with valid agent password
};

# Build GetParams as part of the URL for REST-GET requests
my $QueryParams = $RestClient->buildQuery( %{$GetParams} );
$GetControllerAndRequest .= $QueryParams;

$RestClient->GET($GetControllerAndRequest);

my $GetResponseCode = $RestClient->responseCode();

if ( $GetResponseCode ne '200' ) {
    print "Get request failed, response code was: $GetResponseCode\n";
}
else {

    # If the request was answered correctly, we receive a JSON string here.
    my $ResponseContent = $RestClient->responseContent();

    my $Data = decode_json $ResponseContent;

    # Just to print out the returned Data structure:
    use Data::Dumper;
    print "Get response was:\n";
    print Dumper($Data);

}

# TicketSearch Example
# See the documentation of OTRSGenericInterfaceREST on how to setup
#   - webservice
#   - transport
#   - operations
my $SearchParams = {
    UserLogin => "some agent user login",       # to be filled with valid agent login
    Password  => "some agent user password",    # to be filled with valid agent password
    Queues    => ['Raw'],
};

# Build SearchParams as part of the URL for REST-GET requests
$QueryParams = $RestClient->buildQuery( %{$SearchParams} );
$SearchControllerAndRequest .= $QueryParams;

$RestClient->GET($SearchControllerAndRequest);

# If the host isn't reachable, wrong configured or couldn't serve the requested page:
my $SearchResponseCode = $RestClient->responseCode();

if ( $SearchResponseCode ne '200' ) {
    print "Search request failed, response code was: $SearchResponseCode\n";
}
else {

    # If the request was answered correctly, we receive a JSON string here.
    my $ResponseContent = $RestClient->responseContent();

    my $Data = decode_json $ResponseContent;

    # Just to print out the returned Data structure:
    use Data::Dumper;
    print "Search Response was:\n";
    print Dumper($Data);

}

# TicketCreate Example
# See the documentation of OTRSGenericInterfaceREST on how to setup
# - webservice
# - transport
# - operations
my $CreateOrUpdateParams = {
    UserLogin => "some agent user login",       # to be filled with valid agent login
    Password  => "some agent user password",    # to be filled with valid agent password
    Ticket    => {
        Title        => 'some ticket title',
        Queue        => 'Raw',
        Lock         => 'unlock',
        Type         => 'Unclassified',
        State        => 'new',
        Priority     => '3 normal',
        Owner        => 'some agent user login',
        CustomerUser => 'customer-1',
    },
    Article => {
        Subject     => 'some subject',
        Body        => 'some body',
        ContentType => 'text/plain; charset=utf8',
    },
};

my $CreateJSONParams = encode_json $CreateOrUpdateParams;

my @CreateRequestParam = (
    $CreateControllerAndRequest,
    $CreateJSONParams
);

# We have to use REST-POST requests in order to send UserLogin and Password correctly
# though other REST methods would fit better.
$RestClient->POST(@CreateRequestParam);

# If the host isn't reachable, wrong configured or couldn't serve the requested page:
my $CreateResponseCode = $RestClient->responseCode();

if ( $CreateResponseCode ne '200' ) {
    print "Create request failed, response code was: $CreateResponseCode\n";
}
else {

    # If the request was answered correctly, we receive a JSON string here.
    my $ResponseContent = $RestClient->responseContent();

    my $Data = decode_json $ResponseContent;

    # Just to print out the returned Data structure:
    use Data::Dumper;
    print "Create Response was:\n";
    print Dumper($Data);

}

# TicketUpdate Example
# See the documentation of OTRSGenericInterfaceREST on how to setup
#   - webservice
#   - transport
#   - operations
my $UpdateJSONParams = encode_json $CreateOrUpdateParams;

my @UpdateRequestParam = (
    $UpdateControllerAndRequest,
    $UpdateJSONParams
);

# We have to use REST-PATCH requests in order to send UserLogin and Password correctly
# though other REST methods would fit better.
$RestClient->PATCH(@UpdateRequestParam);

# If the host isn't reachable, wrong configured or couldn't serve the requested page:
my $UpdateResponseCode = $RestClient->responseCode();
if ( $UpdateResponseCode ne '200' ) {
    print "Update request failed, response code was: $UpdateResponseCode\n";
}
else {

    # If the request was answered correctly, we receive a JSON string here.
    my $ResponseContent = $RestClient->responseContent();

    my $Data = decode_json $ResponseContent;

    # Just to print out the returned Data structure:
    use Data::Dumper;
    print "Update response was:\n";
    print Dumper($Data);

}

# TicketHistoryGet Example
# See the documentation of OTRSGenericInterfaceREST on how to setup
#   - webservice
#   - transport
#   - operations
my $HistoryParams = {
    UserLogin => "some agent user login",       # to be filled with valid agent login
    Password  => "some agent user password",    # to be filled with valid agent password
    TicketID  => [1],
};

# Build SearchParams as part of the URL for REST-GET requests
$QueryParams = $RestClient->buildQuery( %{$HistoryParams} );
$HistoryControllerAndRequest .= $QueryParams;

$RestClient->GET($HistoryControllerAndRequest);

# If the host isn't reachable, wrong configured or couldn't serve the requested page:
my $HistoryResponseCode = $RestClient->responseCode();

if ( $HistoryResponseCode ne '200' ) {
    print "History request failed, response code was: $HistoryResponseCode\n";
}
else {

    # If the request was answered correctly, we receive a JSON string here.
    my $ResponseContent = $RestClient->responseContent();

    my $Data = decode_json $ResponseContent;

    # Just to print out the returned Data structure:
    use Data::Dumper;
    print "History Response was:\n";
    print Dumper($Data);

}

                    
                

REST请求的cURL例子

用上面给出的通用工单连接器REST配置的例子,我们可以:

创建工单:在/Ticket路径上使用POST方法。

搜索工单:在/Ticket路径上使用GET方法。

更新工单:在/Ticket/{TicketID}路径上使用PATCH方法,{TicketID}是代表传输配置中:TicketID的模板。

获取工单:在/Ticket/{TicketID}路径上使用GET方法,{TicketID}是代表传输配置中:TicketID的模板。

获取工单历史: 在/TicketHistory/{TicketID}路径上使用GET方法,{TicketID}是代表传输配置中:TicketID的模板。

创建一个新工单

cURL命令:


shell> curl "http://localhost/otrs/nph-genericinterface.pl/Webservice/GenericTicketConnectorREST/Ticket?UserLogin=agent&Password=123" -H "Content-Type: application/json" -d "{\"Ticket\":{\"Title\":\"REST Create Test\", \"Type\": \"Unclassified\", \"Queue\":\"Raw\",\"State\":\"open\",\"Priority\":\"3 normal\",\"CustomerUser\":\"customer\"},\"Article\":{\"Subject\":\"Rest Create Test\",\"Body\":\"This is only a test\",\"ContentType\":\"text/plain; charset=utf8\"}}"  -X POST

                    

响应:

{
  "ArticleID":5484,
  "TicketNumber":"1001936",
  "TicketID":"1686"
}
                    

获取工单详细信息

cURL命令:


curl "http://localhost/otrs/nph-genericinterface.pl/Webservice/GenericTicketConnectorREST/Ticket/1686?UserLogin=agent&Password=123"

                    

响应:

{
  "Ticket": [
    {
      "Age": 777,
      "PriorityID": 3,
      "ServiceID": "",
      "Type": "Unclassified",
      "Responsible": "root@localhost",
      "StateID": 4,
      "ResponsibleID": 1,
      "ChangeBy": 2,
      "EscalationTime": 0,
      "Changed": "2014-06-30 19:08:14",
      "OwnerID": 2,
      "RealTillTimeNotUsed": 0,
      "GroupID": 1,
      "Owner": "agent",
      "CustomerID": "OTRS",
      "TypeID": 1,
      "Created": "2014-06-30 19:08:12",
      "Priority": "3 normal",
      "UntilTime": 0,
      "EscalationUpdateTime": 0,
      "QueueID": 2,
      "Queue": "Raw",
      "State": "open",
      "Title": "REST Create Test",
      "CreateBy": 2,
      "TicketID": 1686,
      "StateType": "open",
      "EscalationResponseTime": 0,
      "UnlockTimeout": 0,
      "EscalationSolutionTime": 0,
      "LockID": 1,
      "TicketNumber": "1001936",
      "ArchiveFlag": "n",
      "Lock": "unlock",
      "CreateTimeUnix": 1404173292,
      "SLAID": "",
      "CustomerUserID": "customer"
    }
  ]
}
                    

更新工单

cURL命令:


curl "http://localhost/otrs/nph-genericinterface.pl/Webservice/GenericTicketConnectorREST/Ticket/1686?UserLogin=agent&Password=123" -H "Content-Type: application/json" -d "{\"Ticket\":{\"Queues\":\"Postmaster\"}}"  -X PATCH

                    

响应:

{
  "TicketNumber":"1001936",
  "TicketID":"1686"
}
                    

搜索工单

cURL命令:


curl "http://localhost/otrs/nph-genericinterface.pl/Webservice/GenericTicketConnectorREST/Ticket?UserLogin=agent&Password=123&Queue=Postmaster"

                    

响应:

{
  "TicketID": [
    "1686",
    "102",
    "100",
    "1"
  ]
}
                    

获取工单历史详情

cURL命令:


curl "http://localhost/otrs/nph-genericinterface.pl/Webservice/GenericTicketConnectorREST/TicketHistory/1686?UserLogin=agent&Password=123"

                    

响应:

{
  "TicketHistory":[
    {
      "History":[
        {
          "CreateBy":1,
          "HistoryType":"NewTicket",
          "TicketID":"1",
          "CreateTime":"2017-06-08 22:44:48",
          "TypeID":1,
          "OwnerID":1,
          "QueueID":1,
          "Name":"New Ticket [2015071510123456] created.",
          "StateID":1,
          "PriorityID":3,
          "ArticleID":"1",
          "HistoryTypeID":1
        }
      ],
      "TicketID":"1"
    }
  ]
}