TQHttpProvider 服务器端使用任何语言编写都可以,但需要其支持 HTTP/HTTPS 协议。
要使用 TQHttpProvider,您需要设置 TQHttpProvider 的以下属性:
- ServiceUrl:该 URL 会被用做对服务器端请求的基准地址来使用,下面是对应的子URL:
(1)、Open:该命令用于打开一个数据库连接
(2)、Close:关闭当前打开的数据库连接
(3)、OpenDataSet:打开一个数据集对象
(4)、ExecSQL:执行一个不返回结果集的 SQL 脚本
(5)、RefreshToken:用于刷新当前令牌,避免令牌过期 - AppId:客户端应用的唯一编码,用来唯一标记一个应用。服务器端应根据这个 appid,去查找对应的 MD5 签名时使用的盐值,以便验证参数是否是有效的参数,以避免被外部调用。
- AppSalt:AppId 对应的用于计算 MD5 哈希值的盐值,用于混淆签名内容。
使用以上代码以后,您就可以按照 QDB 的正常规则使用 TQHttpProvider 访问服务器端的数据库了。那么,接下来的问题就是客户端与服务器端通讯的协议具体约定了:
1、建立连接
命令代码:/Open
命令参数:
- appid :对应于 TQHttpProvider.AppId 属性
- timestamp:当前计算机的时间戳,后续服务器端可以根据该值与服务器时间的差值,来确定是否来自应用的访问,从而避免外部攻击
- database:要连接的数据库的连接字符串,一般来说,为了避免传递敏感信息,应在服务器端定义别名,这里直接传连接的别名,由服务器端进行解析,获取实际的连接参数。
- sign:参数签名,其具体算法是按不区分大小写的参数名称排序,也就是说 AppId 和 appid 计算排序列的位置应该是一样的,然后将各个参数拼接成未进行 URL 编码的字符串,参数名与值之前使用等号连接,参数与参数之间使用 “&” 连接。拼接后的参数字符串 + TQHttpProvider.AppSalt 的值计算 MD5 哈希值并以小写方式赋值给 sign。
返回值:
服务器端应返回一个符合下面格式要求的 JSON 对象:
{ "code":0,//整数错误代码,0 代表成功,其它值意味着失败,具体含义定义由服务器端实现确定 "hint":"",//错误提示消息字符串,如果操作成功,该项被忽略,也就是可以不返回,一般用于提示用户 "help":"",//提供给开发者的出错帮助信息,可能会包含敏感信息,不适宜提供给用户呈现 "result":{ "access_token":"",//会话令牌,后续操作都需要提供该令牌以确定您的信息 "access_expire":7200,//会话有效期,超过有效期,会话需要刷新令牌或者重新打开连接 "refresh_token":"",//刷新令牌,该令牌用于给当前会话“续命”,调用 /RefreshToken 时需要传递该参数 "refresh_expire":2592000//刷新令牌有效期,应大于会话的有效期 } }
您也可以通过服务器在 result 里返回额外的参数给客户端,整个 result 的内容会被记录到 ServerExtParams 属性中。
示例 URL:
https://blog.qdac.cc/qdb/qdb_httppov.php/Open?timestamp=1522357751&sign=b67d447f3cc86b8c1e69368ddb355671&appid=Demos.HttpProvider&database=PgSQLDemo
额外建议:
对于有特殊需要的客户,端参数签名算法可以自定义,可以修改 TQHttpProvider.Rest 函数来完成这一工作。
2、关闭连接
命令代码:/Close
命令参数:
- token:建立连接时得到的会话令牌( access_token )
- timestamp:当前计算机的时间戳
- sign:参数签名,参考 /Open 命令
返回值:
服务器端应返回一个符合下面格式要求的 JSON 对象:
{ "code":0,//整数错误代码,0 代表成功,其它值意味着失败,具体含义定义由服务器端实现确定 "hint":"",//错误提示消息字符串,如果操作成功,该项被忽略,也就是可以不返回,一般用于提示用户 "help":""//提供给开发者的出错帮助信息,可能会包含敏感信息,不适宜提供给用户呈现 }
备注:
无论服务器返回错误代码是何值,都不会影响连接关闭。
示例 URL:
https://blog.qdac.cc/qdb/qdb_httppov.php/Close?token=se3hKEXp0vsqsZgNcSXUqRzcvb6IGBuj&sign=8e9ea60b0cfac8c1b5032fecc71afa98×tamp=1522357651
3、打开数据集
命令代码:/OpenDataSet
命令参数:
- token:建立连接时得到的会话令牌( access_token )
- timestamp:当前计算机的时间戳
- sign:参数签名,参考 /Open 命令
- sql:要查询的 SQL 脚本。如果使用 POST 方式投递,那么它将做为一个 Json 对象的子结点存在,否则当做普通参数参与签名计算。
- transaction:是否需要开启事务,布尔值。如果使用 POST 方式投递,那么它将做为一个 Json 对象的子结点存在,否则当做普通参数参与签名计算。
- params:SQL 参数与值对列表,仅 POST 方式下需要。GET 方式下,参数被直接通过 URL 传递。
返回值:
{ "code":0,//整数错误代码,0 代表成功,其它值意味着失败,具体含义定义由服务器端实现确定 "hint":"",//错误提示消息字符串,如果操作成功,该项被忽略,也就是可以不返回,一般用于提示用户 "help":"",//提供给开发者的出错帮助信息,可能会包含敏感信息,不适宜提供给用户呈现 "result":{ "Fields":[//字段定义列表 { "name":"",//字段名 "table":"",//字段所属表名,非必需 "schema":"",//表所有者,非必需 "category":"",//数据库,非必需 "base_name":"",//数据库原始字段名,非必需 "delphi_type":"",//对应的 Delphi 字段类型,值参考 FieldTypeNames 定义,必需 "len":0,//对应的列长度,非必需 "precision":0,//精度,非必需 "scale":0,//小数点后位数,非必需 "flags":[not_null,primary_key,multiple_key,unique_key,blob]//非必需 }... ] "Records":[//记录列表 []//值列表数组 ,... ] } }
备注:
1、使用 POST 传递 SQL 命令时,JSON 参数格式示例如下:
{ "sql":"select * from information_schema.columns where table_name=:tablename", "transaction":false, "params":{ "tablename":"pg_indexes" } }
2、出于安全考虑,一般不推荐在客户端直接传递 SQL 脚本到服务器端执行。可以使用预定义SQL脚本,然后传别名及参数的方式,执行相应的结果集,具体参考 qdb_httpprov.php 实现。
参考 URL:
https://blog.qdac.cc/qdb/qdb_httppov.php/OpenDataSet?token=QWPRU15npVEzTlvR7kdU9sF7BRsbKQdl×tamp=1522357912&sign=af03500cb0fd5892a302611deffeabf9
4、执行SQL脚本
命令代码:/ExecSQL
参数:
- token:建立连接时得到的会话令牌( access_token )
- timestamp:当前计算机的时间戳
- sign:参数签名,参考 /Open 命令
- sql:要查询的 SQL 脚本。如果使用 POST 方式投递,那么它将做为一个 Json 对象的子结点存在,否则当做普通参数参与签名计算。
- transaction:是否需要开启事务,布尔值。如果使用 POST 方式投递,那么它将做为一个 Json 对象的子结点存在,否则当做普通参数参与签名计算。
- params:SQL 参数与值对列表,仅 POST 方式下需要。GET 方式下,参数被直接通过 URL 传递。
返回值:
{ "code":0,//整数错误代码,0 代表成功,其它值意味着失败,具体含义定义由服务器端实现确定 "hint":"",//错误提示消息字符串,如果操作成功,该项被忽略,也就是可以不返回,一般用于提示用户 "help":"",//提供给开发者的出错帮助信息,可能会包含敏感信息,不适宜提供给用户呈现 "result":0//最后的SQL语句影响的行数 }
备注:
1、使用 POST 传递 SQL 命令时,JSON 参数格式示例如下:
{ "sql":"select * from information_schema.columns where table_name=:tablename", "transaction":false, "params":{ "tablename":"pg_indexes" } }
2、出于安全考虑,一般不推荐在客户端直接传递 SQL 脚本到服务器端执行。可以使用预定义SQL脚本,然后传别名及参数的方式,执行相应的结果集,具体参考 qdb_httpprov.php 实现。