You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
馆际互借操作是图书馆 ILS 系统之间的比较复杂的操作。从它入手开始设计一套 API 是一个比较合适的切入点。
笔者尝试先设计出这一部分的 API,然后再参考其它同类 API 进行优化改进。
一些概念和定义
总体设想
馆际之间的借书还书操作,应该在图书所属图书馆的 ILS 系统和读者所属的图书馆的 ILS 系统中都留下比较完整的信息。因为分布式涉及到一个“民主化”的问题,平行的各个 ILS 系统之间应该是平等协作的关系,信息应当保持透明,适当的冗余存储,和可互证。目的是让馆际互借的各家参与图书馆感到系统可信,操作事务有据可查,系统健壮。
拓扑结构
平行的 ILS 系统之间互相访问和操作,有两种方法,一种是通过一个总的代理服务器调配分发,另外一种是平行的 ILS 系统服务器之间直接一一对应进行交互。
前者,通过总代理服务器调配分发,优点是:
每个平行的 ILS 系统只需要和总代理服务器打交道即可,不必记忆其它平行服务器的地址和账户等信息。这是一种星形的拓扑结构。
缺点是:
需要开发一套总代理服务器,并需要进行日常运维。
后者,平行的 ILS 系统服务器之间直接交互,缺点是:
每个服务器都需要记忆其它 n-1 个服务器的地址和账户等信息。这是一种网状的拓扑结构。
优点是:
避免开发和维护总代理服务器,减少了开发和维护工作量;
分析整个分布式环境的拓扑结构,可以为 API 设计提供指引。最佳的效果是,平行的 ILS 服务器之间的互访 API,和 ILS 服务器和总代理服务器之间互访的 API,应该是同构的。也就是说,不必急于选定拓扑结构,而是把这个问题留到后期决定,甚至动态决定。API 是可以同时满足两种拓扑结构的。
验证读者身份。这一步可以是读者在代理设备(例如自助借还机)上扫描借书卡,然后输入密码,代理设备根据读者号码中的机构代码部分,决定向读者所在馆(也就是本馆) ILS 服务器发出验证请求。(注: 这里其实也可以向总代理服务器发出验证请求)
还可以是一些变化的形态:代理设备打开摄像头,对读者进行人脸识别,核对读者就是借书卡所有者本人。
获得书刊的号码。可以是扫描图书册条码,或者扫描图书 RFID 标签,或者其它识别图书号码的方式。书刊的号码中可以省略机构代码部分。
注:如果步骤 4 失败,代理设备要追加一次对图书进行防盗处理 Undo 的操作。具体来说就是重新对磁条充磁;或者 RFID 标签设置 EAS 为 On。(为何要在发出还书请求之前进行防盗处理,是为了防范读者在步骤 4 之前突然从代理设备上抽走书刊 --- 这样会导致书刊并没有在系统中办理借书手续、然而又可以携带书刊直接从门禁穿过不报警,这样一种漏洞)
外馆读者借书
步骤为:
验证读者身份。这一步可以是读者在代理设备(例如自助借还机)上扫描借书卡,然后输入密码,代理设备根据读者号码中的机构代码部分,决定向读者所在馆 ILS 服务器或者总代理服务器发出验证请求。
还可以是一些变化的形态:代理设备打开摄像头,对读者进行人脸识别,核对读者就是借书卡所有者本人。
获得书刊的号码。可以是扫描书刊册条码,或者扫描图书 RFID 标签,或者其它识别图书号码的方式。注意,书刊的号码应该包含机构代码部分。
代理设备发出借书请求。代理设备将前一步搜集到的读者号码和图书号码,作为参数请求服务器完成借书。和读者在本馆借书不同,这里又分为两步操作:
3.1) 请求读者所在馆 ILS 服务器完成借书。可以直接请求对方 ILS 服务器,也可以经过总代理服务器转达。(这一步如果成功,应当得到一个事务 ID。事务 ID 加上服务器所属单位的机构代码,应当是全局唯一的)
3.2) 请求图书所属馆的 ILS 服务器完成借书。一般是直接请求图书所属馆的 ILS 服务器。其实也可以经过总代理服务器转达。
注意:如果 3.1 步成功了,但到执行 3.2 步的时候失败了,代理设备需要向 3.1 步所请求的服务器追加发出一个取消事务的请求。
代理设备发出还书请求。代理设备将前一步搜集到的读者号码(可选)和图书号码,作为参数请求本馆服务器完成还书。和读者在本馆还书不同,这里又分为两步操作:
4.1) 请求读者所在馆 ILS 服务器完成还书。可以直接请求对方 ILS 服务器,也可以经过总代理服务器转达。(这一步如果成功,应当得到一个事务 ID。事务 ID 加上服务器所属单位的机构代码,应当是全局唯一的)
4.2) 请求图书所属馆的 ILS 服务器完成还书。一般是直接请求图书所属馆的 ILS 服务器。其实也可以经过总代理服务器转达。
注意:如果 4.1 步成功了,但到执行 4.2 步的时候失败了,代理设备需要向 4.1 步所请求的服务器追加发出一个取消事务的请求。
注:如果步骤 4 失败,代理设备要对图书进行防盗处理 Undo。具体来说就是重新对磁条充磁;或者 RFID 标签设置 EAS 为 On。(为何要在发出还书请求之前进行防盗处理,是为了防范读者在步骤 4 之前突然从代理设备上抽走书刊 --- 这样会导致书刊并没有在系统中办理借书手续、然而又可以携带书刊直接从门禁穿过不报警,这样一种漏洞)
读者、书刊、代理设备三方的逻辑关系
受到网络条件(或者安全性)的限制,代理设备有可能只被允许访问本馆的 ILS 服务器。为了实现馆际互借,一些请求会被 ILS 服务器分发,在后台转为请求平行的对方图书馆 ILS 服务器或者总代理服务器。也就是说,代理设备不能访问外界的服务器。
如果没有上述限制,代理服务器可以通过机构代码决定直接访问平行的对方图书馆的 ILS 服务器,或者总代理服务器。
馆际互借操作的关键目标,是让读者所属馆的 ILS 系统记载借还操作信息,并且也让图书所属馆的 ILS 系统记载借还操作信息。这样形成一种略有冗余的,互相印证和锁定的数据布局。
为了避免图书所属馆的 ILS 服务器存储和跟踪外馆读者的账户记录(因为成本和安全性等诸多原因),图书所属馆可以把外馆读者借走本馆图书的行为,理解成这个读者所在图书馆的一个对公账户的借书行为,如果需要追索图书,逻辑上来讲是首先向读者所在图书馆去追索,不会直接去面对那个读者。
这样,那个读者所在图书馆是需要留存读者当初借书操作的详细信息的,一如这个读者借本馆图书的情形的需要。所以设计安排馆际互借操作中,有一步向读者所在馆 ILS 服务器发出请求的道理在这里。
而有一步向图书所属馆 ILS 服务器发出请求,是因为该馆的图书财产被借走,理应存储相关信息以备日后追索。不过值得注意的是,前面提到了一个原则,图书所属馆对这些信息的详细程度受到安全性和保密原则的制约,理论上来说,只需要包含读者所属馆的标识信息和图书标识信息、事务 ID 即可。宽容一点,可以包含读者号码信息。但不应包含读者姓名、身份证号等等敏感信息,这些信息是读者所属馆的服务器负责保存的。
由于书刊可能会在图书馆之间漂流,流动到一个不是读者所属馆和图书所属馆的第三方图书馆,这时候读者可能会在这个当前漂流到的图书馆进行借还操作。等于是利用这个图书馆的设备,向另外两个图书馆的 ILS 服务器发出请求。无论如何,读者和图书号码中具有机构代码,设备(或者被其请求的其本馆 ILS 服务器)是可以搞清楚每一步到底要向哪一方发出请求的。
API 设计草案
在 API 之外另行约定登录鉴权机制。目前可以清楚的一点是,当服务器执行 API 的时候,会认为发起请求的前端是有一个确定的账户身份的,包括前端设备的所属机构代码等信息。
如果是前端设备直接请求其它 ILS 系统的服务器,那么服务器可以明确得知前端的所属机构代码等信息。也就是说前端的身份在 API 虽然在参数中没有包含,但是不言自明。而如果是前端设备直接请求总代理服务器(通过总代理服务器再分发请求到相应的 ILS 系统服务器),那么需要在代理服务器分发请求时,在 http 请求中用一个头字段,或者统一在每个 API 中都增加一个 originalRequestor 参数,用来传递最初请求者的机构代码等信息。
ILS 服务器在执行请求的时候,要根据上述最初请求者的信息,验证请求者的机构代码、账户身份是否与操作相吻合。
GetInstitutionCode
询问当前服务器管辖的机构代码(机构拥有书刊和读者)。注意一个服务器可以同时管辖多个机构代码。
如果服务器是一个图书馆的 ILS 服务器,则应答本馆的机构代码。如果服务器是一个总代理服务器,则可以应答负责中转的所有 ILS 服务器的机构代码。
安全性考量:
服务器可能会撒谎。不能完全相信一个服务器以本 API 应答的机构代码。因此需要一些线下的可靠方式来确定机构代码对应的服务器的地址,避免把请求发给了错误的服务器。也可以考虑使用一些加密技术来进行保护,让错误的服务器无法解密和查看请求参数信息。
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
来源:https://jihulab.com/apiforum/public/-/issues/9
馆际互借 API 设计分析
缘起
馆际互借操作是图书馆 ILS 系统之间的比较复杂的操作。从它入手开始设计一套 API 是一个比较合适的切入点。
笔者尝试先设计出这一部分的 API,然后再参考其它同类 API 进行优化改进。
一些概念和定义
总体设想
馆际之间的借书还书操作,应该在图书所属图书馆的 ILS 系统和读者所属的图书馆的 ILS 系统中都留下比较完整的信息。因为分布式涉及到一个“民主化”的问题,平行的各个 ILS 系统之间应该是平等协作的关系,信息应当保持透明,适当的冗余存储,和可互证。目的是让馆际互借的各家参与图书馆感到系统可信,操作事务有据可查,系统健壮。
拓扑结构
平行的 ILS 系统之间互相访问和操作,有两种方法,一种是通过一个总的代理服务器调配分发,另外一种是平行的 ILS 系统服务器之间直接一一对应进行交互。
前者,通过总代理服务器调配分发,优点是:
缺点是:
后者,平行的 ILS 系统服务器之间直接交互,缺点是:
优点是:
分析整个分布式环境的拓扑结构,可以为 API 设计提供指引。最佳的效果是,平行的 ILS 服务器之间的互访 API,和 ILS 服务器和总代理服务器之间互访的 API,应该是同构的。也就是说,不必急于选定拓扑结构,而是把这个问题留到后期决定,甚至动态决定。API 是可以同时满足两种拓扑结构的。
机构代码
在馆际互借的环境中,一般来说读者和图书往往不属于同一个图书馆,所以无论读者号码还是图书号码,都应该是一种包含机构代码部分的全局性号码。形态为:
机构代码.图书号码
或
机构代码.读者号码
当一个读者在本馆内,对本馆的图书进行借书还书操作的时候,处理过程可以酌情简化上述号码,即省略机构代码部分,形态为:
图书号码
或
读者号码
也就是说,如果字符串中没有点,那就理解为缺省了机构代码部分。
值得注意的是,一个读者在进行借书还书操作的时候,可能是在第三方图书馆的设备上进行。即,读者属于第一个图书馆,图书属于第二个图书馆,设备属于第三个图书馆。这是最复杂的情况。思考这种极端情况,有助于设计出一套完备的 API。
请求方和响应方
按照一般 Client/Server 模式的惯例,有请求方和响应方两种角色。Client 发出请求,Server 收到请求以后,返回响应结果。注意 Server 永远不会主动请求 Client。
整个环境中,可能存在很多种角色。包括每个平行的 ILS 系统的服务器,和这些服务器的前端模块,以及代理服务器。
注意服务器模块之间可以互相访问,当一个服务器请求另外一个服务器的时候,前者是请求者、后者是响应者。每个服务器既可以扮演请求方,也可以扮演响应方,这是由具体功能决定的。
前端模块则只会扮演请求方,不会扮演响应方。
分布式事务
用什么方式来实现分布式的事务,是一个值得研讨的课题。有以下可选方法:
操作流程分析
本馆读者借书
这是普通 ILS 系统都有的功能。
步骤为:
验证读者身份。这一步可以是读者在代理设备(例如自助借还机)上扫描借书卡,然后输入密码,代理设备根据读者号码中的机构代码部分,决定向读者所在馆(也就是本馆) ILS 服务器发出验证请求。(注: 这里其实也可以向总代理服务器发出验证请求)
还可以是一些变化的形态:代理设备打开摄像头,对读者进行人脸识别,核对读者就是借书卡所有者本人。
获得书刊的号码。可以是扫描图书册条码,或者扫描图书 RFID 标签,或者其它识别图书号码的方式。书刊的号码中可以省略机构代码部分。
代理设备发出借书请求。代理设备将前一步搜集到的读者号码和图书号码,作为参数请求本馆服务器完成借书。
代理设备对图书进行防盗处理。具体来说就是磁条消磁;或者 RFID 标签设置 EAS 为 Off。
本馆读者还书
这是普通 ILS 系统都有的功能。
步骤为:
验证读者身份。方法同借书操作时的验证读者身份。这一步是可选操作。也就是说读者可以选择“验证还书”和“非验证还书”,后者不需要验证读者身份。
获得书刊的号码。方法同借书操作时的这一步。
代理设备对图书进行防盗处理。具体来说就是磁条充磁;或者 RFID 标签设置 EAS 为 On。
代理设备发出还书请求。代理设备将前一步搜集到的读者号码(可选)和图书号码,作为参数请求本馆服务器完成还书。
注:如果步骤 4 失败,代理设备要追加一次对图书进行防盗处理 Undo 的操作。具体来说就是重新对磁条充磁;或者 RFID 标签设置 EAS 为 On。(为何要在发出还书请求之前进行防盗处理,是为了防范读者在步骤 4 之前突然从代理设备上抽走书刊 --- 这样会导致书刊并没有在系统中办理借书手续、然而又可以携带书刊直接从门禁穿过不报警,这样一种漏洞)
外馆读者借书
步骤为:
验证读者身份。这一步可以是读者在代理设备(例如自助借还机)上扫描借书卡,然后输入密码,代理设备根据读者号码中的机构代码部分,决定向读者所在馆 ILS 服务器或者总代理服务器发出验证请求。
还可以是一些变化的形态:代理设备打开摄像头,对读者进行人脸识别,核对读者就是借书卡所有者本人。
获得书刊的号码。可以是扫描书刊册条码,或者扫描图书 RFID 标签,或者其它识别图书号码的方式。注意,书刊的号码应该包含机构代码部分。
代理设备发出借书请求。代理设备将前一步搜集到的读者号码和图书号码,作为参数请求服务器完成借书。和读者在本馆借书不同,这里又分为两步操作:
3.1) 请求读者所在馆 ILS 服务器完成借书。可以直接请求对方 ILS 服务器,也可以经过总代理服务器转达。(这一步如果成功,应当得到一个事务 ID。事务 ID 加上服务器所属单位的机构代码,应当是全局唯一的)
3.2) 请求图书所属馆的 ILS 服务器完成借书。一般是直接请求图书所属馆的 ILS 服务器。其实也可以经过总代理服务器转达。
注意:如果 3.1 步成功了,但到执行 3.2 步的时候失败了,代理设备需要向 3.1 步所请求的服务器追加发出一个取消事务的请求。
代理设备对图书进行防盗处理。具体来说就是磁条消磁;或者 RFID 标签设置 EAS 为 Off。
注:如果读者在步骤 4 之前突然从代理设备上抽走书刊,导致防盗处理没有完成,这时候读者携带书刊穿过门禁的时候会报警。此时需要让读者回到代理设备上执行一次纠正书刊防盗状态的操作,然后就可以穿过门禁了。
外馆读者还书
步骤为:
验证读者身份。方法同借书操作时的验证读者身份。这一步是可选操作。也就是说读者可以选择“验证还书”和“非验证还书”,后者不需要验证读者身份。
获得书刊的号码。方法同借书操作时的这一步。
代理设备对图书进行防盗处理。具体来说就是磁条充磁;或者 RFID 标签设置 EAS 为 On。
代理设备发出还书请求。代理设备将前一步搜集到的读者号码(可选)和图书号码,作为参数请求本馆服务器完成还书。和读者在本馆还书不同,这里又分为两步操作:
4.1) 请求读者所在馆 ILS 服务器完成还书。可以直接请求对方 ILS 服务器,也可以经过总代理服务器转达。(这一步如果成功,应当得到一个事务 ID。事务 ID 加上服务器所属单位的机构代码,应当是全局唯一的)
4.2) 请求图书所属馆的 ILS 服务器完成还书。一般是直接请求图书所属馆的 ILS 服务器。其实也可以经过总代理服务器转达。
注意:如果 4.1 步成功了,但到执行 4.2 步的时候失败了,代理设备需要向 4.1 步所请求的服务器追加发出一个取消事务的请求。
注:如果步骤 4 失败,代理设备要对图书进行防盗处理 Undo。具体来说就是重新对磁条充磁;或者 RFID 标签设置 EAS 为 On。(为何要在发出还书请求之前进行防盗处理,是为了防范读者在步骤 4 之前突然从代理设备上抽走书刊 --- 这样会导致书刊并没有在系统中办理借书手续、然而又可以携带书刊直接从门禁穿过不报警,这样一种漏洞)
读者、书刊、代理设备三方的逻辑关系
受到网络条件(或者安全性)的限制,代理设备有可能只被允许访问本馆的 ILS 服务器。为了实现馆际互借,一些请求会被 ILS 服务器分发,在后台转为请求平行的对方图书馆 ILS 服务器或者总代理服务器。也就是说,代理设备不能访问外界的服务器。
如果没有上述限制,代理服务器可以通过机构代码决定直接访问平行的对方图书馆的 ILS 服务器,或者总代理服务器。
馆际互借操作的关键目标,是让读者所属馆的 ILS 系统记载借还操作信息,并且也让图书所属馆的 ILS 系统记载借还操作信息。这样形成一种略有冗余的,互相印证和锁定的数据布局。
为了避免图书所属馆的 ILS 服务器存储和跟踪外馆读者的账户记录(因为成本和安全性等诸多原因),图书所属馆可以把外馆读者借走本馆图书的行为,理解成这个读者所在图书馆的一个对公账户的借书行为,如果需要追索图书,逻辑上来讲是首先向读者所在图书馆去追索,不会直接去面对那个读者。
这样,那个读者所在图书馆是需要留存读者当初借书操作的详细信息的,一如这个读者借本馆图书的情形的需要。所以设计安排馆际互借操作中,有一步向读者所在馆 ILS 服务器发出请求的道理在这里。
而有一步向图书所属馆 ILS 服务器发出请求,是因为该馆的图书财产被借走,理应存储相关信息以备日后追索。不过值得注意的是,前面提到了一个原则,图书所属馆对这些信息的详细程度受到安全性和保密原则的制约,理论上来说,只需要包含读者所属馆的标识信息和图书标识信息、事务 ID 即可。宽容一点,可以包含读者号码信息。但不应包含读者姓名、身份证号等等敏感信息,这些信息是读者所属馆的服务器负责保存的。
由于书刊可能会在图书馆之间漂流,流动到一个不是读者所属馆和图书所属馆的第三方图书馆,这时候读者可能会在这个当前漂流到的图书馆进行借还操作。等于是利用这个图书馆的设备,向另外两个图书馆的 ILS 服务器发出请求。无论如何,读者和图书号码中具有机构代码,设备(或者被其请求的其本馆 ILS 服务器)是可以搞清楚每一步到底要向哪一方发出请求的。
API 设计草案
在 API 之外另行约定登录鉴权机制。目前可以清楚的一点是,当服务器执行 API 的时候,会认为发起请求的前端是有一个确定的账户身份的,包括前端设备的所属机构代码等信息。
如果是前端设备直接请求其它 ILS 系统的服务器,那么服务器可以明确得知前端的所属机构代码等信息。也就是说前端的身份在 API 虽然在参数中没有包含,但是不言自明。而如果是前端设备直接请求总代理服务器(通过总代理服务器再分发请求到相应的 ILS 系统服务器),那么需要在代理服务器分发请求时,在 http 请求中用一个头字段,或者统一在每个 API 中都增加一个 originalRequestor 参数,用来传递最初请求者的机构代码等信息。
ILS 服务器在执行请求的时候,要根据上述最初请求者的信息,验证请求者的机构代码、账户身份是否与操作相吻合。
GetInstitutionCode
询问当前服务器管辖的机构代码(机构拥有书刊和读者)。注意一个服务器可以同时管辖多个机构代码。
如果服务器是一个图书馆的 ILS 服务器,则应答本馆的机构代码。如果服务器是一个总代理服务器,则可以应答负责中转的所有 ILS 服务器的机构代码。
安全性考量:
服务器可能会撒谎。不能完全相信一个服务器以本 API 应答的机构代码。因此需要一些线下的可靠方式来确定机构代码对应的服务器的地址,避免把请求发给了错误的服务器。也可以考虑使用一些加密技术来进行保护,让错误的服务器无法解密和查看请求参数信息。
请求参数:
string queryWord
响应参数:
string errorCode
string errorInfo
Institution [] Institutions (返回机构代码列表)
VerifyPatron()
验证读者身份
请求参数:
string patronUID
string password
响应参数:
string errorCode
string errorInfo
CheckOut()
借书
安全性考量:
服务器应该注意检查请求参数中的机构代码,如果发现不属于自己管辖的机构代码,要对 API 返回适当的错误码。
请求参数:
string patronUID
string itemUID
string policy (政策。借书期限选择等参数)
响应参数:
string errorCode
string errorInfo
string transaction (交易信息。交易 ID 等)
string patronInfo (读者信息。用于界面显示)
string bookInfo (图书信息。用于界面显示)
Renew
续借
基本同“CheckOut”
CheckIn()
还书
请求参数:
string patronUID(可选)
string itemUID
响应参数:
string errorCode
string errorInfo
string transaction (交易信息。交易 ID 等)
string patronInfo (读者信息。用于界面显示)
string bookInfo (图书信息。用于界面显示。其中永久馆藏地字段可以帮助馆员进行后续分堆操作)
string reservationInfo (预约到书通知信息,分堆建议)
All reactions