开发usb接口转换器时,我使用php语言,合作方的usb接口转换器给出的是java加解签demo,php应该怎么做?

当前位置: >>
php api接口编写教程
如何开发 api 接口 ......................................................... 1 PHP 接口开发签名验证原理详解 ............................................ 3 使用 php 定义自己的 API 接口 ...................................
........... 8 Api 接口文档范例 ........................................................ 10 Web Service 的工作原理 ................................................. 23 RESTful API 设计最佳实践 ............................................... 31如何开发 api 接口API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发 人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。 API 函数包含在 Windows 系统目录下的动态连接库文件中。 Windows API 是一套用来控制 Windows 的各个部件的 外观和行为的预先定义的 Windows 函数。 用户的每个动作都会引发一个或几个函数的运行以告诉 Windows 发生了 什么。这在某种程度上很像 Windows 的天然代码。而其他的语言只是提供一种能自动而且更容易的访问 API 的方 法。当你点击窗体上 的一个按钮时,Windows 会发送一个消息给窗体,VB 获取这个调用并经过分析后生成一个特 定事件。 更易理解来说:Windows 系统除了协调 应用程序的执行、内存的分配、系统资源的管理外,同时他也是一个很大 的服务中心。调用这个服务中心的各种服务(每一种服务就是一个函数)可以帮助应用程序 达到开启视窗、描绘图形 和使用周边设备等目的,由于这些函数服务的对象是应用程序,所以称之为 Application Programming Interface, 简称 API 函数。WIN32 API 也就是 MicrosoftWindows 32 位平台的应用程序编程接口。 凡是在 Windows 工作环境底下执行的应用程序,都可以调用 Windows API。 linux API在 linux 中,用户编程接口 API 遵循了 UNIX 中最流行的应用编程界面标准---POSIX 标准。POSIX 标准是由 IEEE 和 ISO/IEC 共同开发 的标准系统。该标准基于当时现有的 UNIX 实践和经验,描述了操作系统的系统调用编程接 口 API,用于保证应用程序可以在源程序一级上在多种操作系统上移 植运行。这些系统调用编程接口主要是通过 C 库(LIBC)来实现的。 2 开放平台基于互联网的应用正变得越来越普及,在这个过程中,有更多的站点将自身的资源开放给开发者来调用。对外提供 的 API 调用使得站点之间的内容关联性更强, 同时这些开放的平台也为用户、 开发者和中小网站带来了更大的价值。 开放是目前的发展趋势,越来越多的产品走向开放。目前的网站不能靠限制用户离开来留住用户,开放的架构反而 更增加了用户的粘性。在 Web 2.0 的浪潮到来之前,开放的 API 甚至源代码主要体现在桌面应用上,而现在越来 越多的 Web 应用面向开发者开放了 API。 具备分享、标准、去中心化、开放、模块化的 Web 2.0 站点,在为使用者带来价值的同时,更希望通过开放的 API 来让站点提供的服务拥有更大的用户群和服务访问数量。 站点在推出基于开放 API 标准的产品和服务后, 无需花费力气做大量的市场推广, 只要提供的服务或应用出色易用, 其他站点就会主动将开放 API 提供的服务整合到自己的应用之中。同时,这种整合 API 带来的服务应用,也会激 发更多富有创意的应用产生。 为了对外提供统一的 API 接口,需要对开发者开放资源调用 API 的站点提供开放统一的 API 接口环境,来帮助使 用者访问站点的功能和资源。 当然,开放 API 的站点为第三方的开发者提供良好的社区支持也是很有意义的,这有助于吸引更多的技术人员参与 到开放的开发平台中,并开发出更为有趣的第三方应用。 视频云技术提供商 CC 视频开放 API 接口,用户可以在自己的网站后台轻松完成视频的上传、视频播放控制操作, 并可批量获取视频及平台信息。 正 如在&什么是 API&中所说,API 函数包含在位于系统目录下的 DLL 文件中。你可以自己输入 API 函数的声明,但 VB 提供了一种更简单的方法,即使用 API Text Viewer。要想在你的工程中声明 API 函数, 只需运行 API Text Viewer, 打开 Win32api.txt 或 MDB。如果你已经把它转换成了数据库的话,这样可以加快速度。 使用预定义的常量和类型 也是同样的方法。 API 除了有应用“应用程序接口”的意思外,还特指 API 的说明文档,也称为帮助文档。 假设你想在你的窗体模块中声明一个函数,粘贴然后运 行,VB 会告诉你:编译错误...Declare 语句不允许作为类 或对象模块中的 Public(公共的) 成员。..看起来很糟糕,其实你需要做的只是在声明前面添加一个 Private(私有的)。 不要忘了,可是这将使该函数只在该窗体模块可用。. 在有些情况下,你会得到&不明确的名称&这样的提示,这是因 为函数、常量或其他的什么东西共用了一个名称。由于绝大多数的函数都进行了别名化,亦即意味着 你可以通过 Alias 子句使用其它的而不是他们原有的名称,你只需简单地改变一下函数名称而它仍然可以正常运行。 远程过程调用(RPC):通过作用在共享数据缓存器上的过程(或任务)实现程序间的通信。 标准查询语言(SQL):是标准的访问数据的查询语言,通过通用数据库实现应用程序间的数据共享。 文件传输:文件传输通过发送格式化文件实现应用程序间数据共享。 信息交付:指松耦合或紧耦合应用程序间的小型格式化信息,通过程序间的直接通信实现数据共享。 当 前应用于 API 的标准包括 ANSI 标准 SQL API。 另外还有一些应用于其它类型的标准尚在制定之中。 API 可以 应用于所有计算机平台和操作系统。这些 API 以不同的格式连接数据。每种数据格式要求以不同的数据命令和参数 实现正确的数据通信,但同时也会产生不同类型的错误。因此,除了具备执行数据共享任务所需 的知识以外,这些 类型的 API 还必须解决很多网络参数问题和可能的差错条件, 即每个应用程序都必须清楚自身是否有强大的性能支 持程序间通信。相反由于这种 API 只处理一种信息格式,所以该情形下的信息交付 API 只提供较小的命令、网络 参数以及差错条件子集。正因为如此,交付 API 方式大大降低了系统复杂性,所以当应用程序需要通过多个平台实 现数据共享时,采用信息交付 API 类型是比较理想的选择。 API 接口属于一种操作系统或程序接口,GUI 接口属于一种图形操作系统。两者都属于直接用户接口。有时公司会 将 API 作为其公共开放系统。也就是说,公司制定自己的系统接口标准,当需要执行系统整合、自定义和程序应 用等操作时,公司所有成员都可以通过该接口标准调用源代 码,该接口标准被称之为开放式 API。PHP 接口开发签名验证原理详解接口签名现在在应用开发中我们通常会用到了,像做支付接口时就必须要用到接口签名了,我们下面来看一个简单的 在 app 应用中的接口签名实现原理了.接口开发是各系统之间对接的重要方式,其数据是通过开放的互联网传输,对数据的安全性要有一定要求,为了提高传 输过程参数的防篡改性,签名 sign 的方式是目前比较常用的方式. 我这里介绍一种方式,是目前国内互联网公司常用的一种方式,其中淘宝的支付宝支付接口、淘宝开放平台接口、腾 讯开放平台等应用的一种方式.一、签名参数 sign 生成的方法第 1 步:将所有参数(注意是所有参数),除去 sign 本身,以及值是空的参数,按参数名字母升序排序.第 2 步: 然后把排序后的参数按参数 1 值 1 参数 2 值 2…参数 n 值 n(这里的参数和值必须是传输参数的原始值, 不能是经过处理的,如不能将&转成”后再拼接)的方式拼接成一个字符串。第 3 步: 把分配给接入方的验证密钥 key 拼接在第 2 步得到的字符串前面。第 2 步: 在上一步得到的字符串前面加上验证密钥 key(这里的密钥 key 是接口提供方分配给接口接入方的), 然后计 算 md5 值,得到 32 位字符串,然后转成大写.第 4 步: 计算第 3 步字符串的 md5 值(32 位),然后转成大写,得到的字符串作为 sign 的值。举例:假设传输的数据是/interface.php?sign=sign_value&p2=v2& p1=v1&method=cancel&p3=&pn=vn(实际情况最好是 通过 post 方式发送),其中 sign 参数对应的 sign_value 就是签名的值。第一步,拼接字符串,首先去除 sign 参数本身,然后去除值是空的参数 p3,剩下 p2=v2&p1=v1& method=cancel&pn=vn,然后按参数名字符升序排序,method=cancel&p1=v1&p2=v2&pn=vn.第二步,然后做参数名和值的拼接,最后得到 methodcancelp1v1p2v2pnvn第三步,在上面拼接得到的字符串前加上验证密钥 key,我们假设是 abc,得到新的字符串 abcmethodcancelp1v1p2v2pnvn 第四步,然后将这个字符串进行 md5 计算,假设得到的是 abcdef,然后转为大写,得到 ABCDEF 这个值即为 sign 签名值。注意,计算 md5 之前请确保接口与接入方的字符串编码一致,如统一使用 utf-8 编码或者 GBK 编码,如果编码方式 不一致则计算出来的签名会校验失败。二、签名验证方法:根据前面描述的签名参数 sign 生成的方法规则,计算得到参数的签名值,和参数中通知过来的 sign 对应的参数值进行 对比,如果是一致的,那么就校验通过,如果不一致,说明参数被修改过.例子,代码如下:1. &?php 2. //header('Content-Type: text/ charset=utf-8'); 3. include_once(dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'phpsec'.DIRECTORY_SEPARATOR.'Math'.DIRECTORY_SEPARATOR.'BigInteger.php');4. include_once(dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'phpsec'.DIRECTORY_SEPARATOR.'Crypt'.DIRECTORY_SEPARATOR.'AES.php');5. include_once(dirname(dirname(__FILE__)).DIRECTORY_SEPARATOR.'phpsec'.DIRECTORY_SEPARATOR.'Crypt'.DIRECTORY_SEPARATOR.'RSA.php');6. //密文 7. $crypttext = 'v66YKULHFld2JElhm/J9qik2Edr1JHdZIc/k/OesU2GbTX2usXyvF4jGvzvoihrrE8FsfKmllmjsMIjO5fdrS/FD20bYFii4JW3BO3bzshXmz6AEs2DWwG4sK9mNojfOC0IsMo V311X5/JlgUoQXkDy4F5HHpYE9d/xGb0g2XE/hnGSSy2cpQcvQtBlBmixwSckNhsEG92l ovlOz8ULwkqG5o7x+qB7P/EMII/WaFAXBJXDXvZX7lmGcOgon6wLhKJLGXorP6BIxOg6 LGc6Ux7BAt3i9+0lujNgxIq/sDsl23hsr3yOUpV5C5a813nrHx4HJyd/hBT1UvIUml+eTmJw WCpSfs2cvxIUr0CE57JAZVyXjK13shK3IsZHLPPsm/JcDCrdy0Co/d5uIGJAdzXdsQ56xsj u+tlvnA1J6yq2tDIfYK/x6k911A5WXLKYxztD1nq+bTYN3Gv/WFfrzVtgWQBrh06ihS2cwvn a0S9EV/YPmhnAjJmrX4trNr9NXQ9xaZaW4lGRg87U5QDV+nQjj1THk0XHFc69N9g2+Ds AGyEs9tK6U0ZQ72hJZqZhBCDH1UKw0PLyIhJdxpgPPOWGp8/QVVU2julTeKunvgAAE c3n+GoZfqjsCDi1S6T2MTnjWYWNoFRBhvEZFD/revgpasTOzDQa5NqR1B+mUF70r6uw 6MWLJ7cT9Tz3jq+CA';8. $aeskey = base64_decode('qZe60QZFxuirub2ey4+7+Q=='); 9. //AES 解密,采用 ECB 模式 10. $aes = new Crypt_AES(CRYPT_MODE_ECB); 11. //设置 AES 密钥 12. $aes-&setKey($aeskey); 13. //解密 AES 密文 14. $plaintext = $aes-&decrypt(base64_decode($crypttext)); 15. echo $ 16. echo '&hr /&'; 17. //AES 加密明文 18. //echo $aes-&encrypt($plaintext); 19. //rsa 公钥 20. $publickey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCffOeIVYut9jW5w1L5uKX4aDvd837a8JhaWm5S8YqNQfgEmfD9T+rDknXLqMT+DXeQAqGo4hBmcbej1ao Mzn6hIJHk3/TfTAToNN8fgwDotHewsTCBbVkQWtDTby3GouWToVsRi1i/A0Vfb0+xM8M nF46DdhhrnZrycERBSbyrcwIDAQAB';21. //echo base64_decode($publickey); 22. //rsa 签名 23. $signature = 'XHin4uUFqrKDEhKBD/hQisXLFFSxM6EZCvCPqnWCQJq3uEp3ayxmFuUgVE0Xoh4AIWjIIsOWdnaToL1bXvAFKwjCtXnkaRwUpvWrk+Q0eqwsoAdywsVQDEceG5 stas1CkPtrznAIW2eBGXCWspOj+aumEAcPyYDxLhDN646Krzw=';24. //echo base64_decode($signature); 25. $rsa = new Crypt_RSA(); 26. //设 置 RSA 签 名 模式 CRYPT_RSA_SIGNATURE_PSS or CRYPT_RSA_SIGNATURE_PKCS127. $rsa-&setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1); 28. //var_dump($rsa-&createKey()); 29. //生成 RSA 公钥、私钥 30. //extract($rsa-&createKey()); 31. //使用 RSA 私钥生成签名 32. //$rsa-&loadKey($privatekey); 33. //$signature = $rsa-&sign($plaintext); 34. //使用 RSA 公钥验证签名 35. echo $ 36. $rsa-&loadKey(base64_decode($publickey)); 37. echo $rsa-&verify($plaintext, base64_decode($signature)) ? 'verified' : 'unverified';//phpfe38. echo '&hr /&'; 39. //生成 RSA 公钥、私钥 40. //var_dump($rsa-&createKey()); 41. extract($rsa-&createKey()); 42. //使用 RSA 私钥加密数据 43. $rsa-&loadKey($privatekey); 44. $ciphertext = $rsa-&encrypt($plaintext); 45. //使用 RSA 公钥解密数据 46. $rsa-&loadKey($publickey); 47. echo $rsa-&decrypt($ciphertext); 48. ?&使用 php 定义自己的 API 接口下面是使用 php 访问数据库并定义 API 接口以供其他应用调用的代码: &?php require_once('../Connections/connect.php'); ?& &?php //引入 json.php 文件,里面是我已经写好的函数:JSON 函数 require_once('json.php'); if (isset($_GET['userid']) ) { //这里是访问数据库,都懂的 mysql_select_db($database_connect, $connect); $userid = $_GET['userid']; $sql_userinfo= &SELECT * FROM user WHERE user_id='$userid'&; $record_userinfo = mysql_query($sql_userinfo, $connect) or die(mysql_error()); $row_userinfo = mysql_fetch_assoc($record_userinfo); //有时不能将所有信息都传给前台,所以不能直接发送$row_userinfo 变量 //echo JSON($row_userinfo);//这里就是将数组转换为 json 数据 //下面将感兴趣的值放到$array 数组里 $array['user_id']=$row_userinfo['user_id']; $array['user_name']=$row_userinfo['user_name']; $array['cellphone']=$row_userinfo['cellphone']; echo JSON($array);//这里就是将数组转换为 json 数据 ?&下面是 json.php 的代码: &?php function arrayRecursive(&$array, $function, $apply_to_keys_also = false) { static $recursive_counter = 0; if (++$recursive_counter & 1000) { die('possible deep recursion attack'); } foreach ($array as $key =& $value) { if (is_array($value)) { arrayRecursive($array[$key], $function, $apply_to_keys_also); } else { $array[$key] = $function($value); }if ($apply_to_keys_also && is_string($key)) { $new_key = $function($key); if ($new_key != $key) { $array[$new_key] = $array[$key]; unset($array[$key]); } } Api 接口文档范例成都世纪东方[] API 接口规范文档更新内容: Whois 查询增加注册信息显示
增加域名修改信息接口
增加域名 Whois 信息查询
正式启用 API 接口说明:API 支持 GET/POST 方式,建议使用 POST 方式。 所有 POST 数据必须使用 UTF-8 编码对数据进行 URLEncode 除获取服务器时间外的其他接口,每次请求都需要进行身份验证。 建议使用获取服务器时间接口来获得 vtime 值。1、获取服务器时间接口 URL 地址: http://www./api-get-time.html返回信息: &?xml version=&1.0& encoding=&utf-8& ?& &interface& &time&33&/time& &/interface& 返回信息说明: time 值:14 位时间值,用于身份验证的 14 位时间戳2、身份验证方法 URL 地址: 参见下列接口 URL 地址 参数: username vtime checksum 用户名 14 位时间戳 验证字串 = MD5(username + MD5(用户密码) + vtime)2、域名查询接口 GET/POST 地址: http://www./api-product-domain-query.html 参数: domain 正常返回信息: &?xml version=&1.0& encoding=&utf-8& ?& &interface& &return_code&&![CDATA[ 200 ]]&&/return_code& &return_msg&&![CDATA[ 验证通过 ]]&&/return_msg& &check& &domain&&/domain& &status&200&/status& &msg&可以注册&/msg& 域名,如: ,,domain.cc 多个域名使用逗号间隔 &/check& &check& &domain&&/domain& &status&201&/status& &msg&不可注册&/msg& &/check& &check& &domain&domain.cc&/domain& &status&433&/status& &msg&查询失败&/msg& &/check& &check& &domain&domain.aaa&/domain& &status&500&/status& &msg&错误的域名&/msg& &/check& &/interface& 异常返回信息: &?xml version=&1.0& encoding=&utf-8& ?& &interface& &return_code&&![CDATA[ 433 ]]&&/return_code& &return_msg&&![CDATA[ 异常详细信息 ]]&&/return_msg& &/interface& 返回参数说明: return_code 返回状态代码,成功 = 200 return_msg domain = 域名返回详细提示信息status = 域名查询状态代码 200 = 可以注册 201 = 不可注册 433 = 查询失败 500 = 错误的域名 msg = 详细说明2、域名注册接口 GET/POST 地址: http://www./api-product-domain-buy.html 参数: domain year dns1 dns2 dom_cn fn_cn ln_cn country_cn provinces_cn city_cn address_cn 域名,如:
注册年限(1-5)年 主要 DNS 服务器 备用 DNS 服务器 域名所有者(中文) 姓(中文) 名(中文) 国家代码(中文) 中国 省份(中文) 城市(中文) 地址(中文) 四川 成都 成都市 XXX
成都世纪东方网络通信有限公司 小 明 dom_en fn_en ln_en country_en provinces_en city_en address_en域名所有者(英文) 姓(英文) 名(英文) 国家代码(英文) CN 省份(英文) 城市(英文) 地址(英文)Oriental Century Xiao MingSichuan Chengdu Chengdu Citypostcode 邮政编码 tel fax email 正常返回信息: 电话号码 传真号码 电子邮件. +86. &?xml version=&1.0& encoding=&utf-8& ?& &interface& &return_code&&![CDATA[ 200 ]]&&/return_code& &return_msg&&![CDATA[ 注册成功 ]]&&/return_msg& &/interface& 异常返回信息: &?xml version=&1.0& encoding=&utf-8& ?& &interface& &return_code&&![CDATA[ 433 ]]&&/return_code& &return_msg&&![CDATA[ 异常详细信息 ]]&&/return_msg& &/interface& 返回参数说明: return_code return_msg返回状态代码,成功 = 200 返回详细提示信息3、域名续费接口 GET/POST 地址: http://www./api-product-domain-renew.html 参数: domain year expiredate 正常返回信息: &?xml version=&1.0& encoding=&utf-8& ?& &interface& &return_code&&![CDATA[ 200 ]]&&/return_code& &return_msg&&![CDATA[ 续费成功 ]]&&/return_msg& &/interface& 异常返回信息: &?xml version=&1.0& encoding=&utf-8& ?& &interface& &return_code&&![CDATA[ 433 ]]&&/return_code& &return_msg&&![CDATA[ 异常详细信息 ]]&&/return_msg& &/interface& 返回参数说明: return_code return_msg 返回状态代码,成功 = 200 返回详细提示信息 域名,如:
续费年限(1-5)年 域名当前过期日期,如: 4、获取域名信息接口 GET/POST 地址: http://www./api-product-domain-view.html 参数: domain 正常返回信息: &?xml version=&1.0& encoding=&utf-8& ?& &interface& &return_code&&![CDATA[ 200 ]]&&/return_code& &return_msg&&![CDATA[ 验证通过 ]]&&/return_msg& 域名,如: &domain&&![CDATA[
]]&&/domain& &password&&![CDATA[ 123456 ]]&&/password& &buydate&&![CDATA[
]]&&/buydate& &expiredate&&![CDATA[
]]&&/expiredate& &dns1&&![CDATA[
]]&&/dns1& &dns2&&![CDATA[
]]&&/dns2&&dom_en&&![CDATA[ XX Company ]]&&/dom_en& &fn_en&&![CDATA[ FirstName ]]&&/fn_en& &ln_en&&![CDATA[ LastName ]]&&/ln_en& &country_en&&![CDATA[ CN ]]&&/country_en& &provinces_en&&![CDATA[ Beijing ]]&&/provinces_en& &city_en&&![CDATA[ Beijing ]]&&/city_en& &address_en&&![CDATA[ Beijing City ]]&&/address_en&&dom_cn&&![CDATA[ 某某公司 ]]&&/dom_cn& &fn_cn&&![CDATA[ 小 ]]&&/fn_cn& &ln_cn&&![CDATA[ 李 ]]&&/ln_cn& &country_cn&&![CDATA[ 中国 ]]&&/country_cn& &provinces_cn&&![CDATA[ 北京 ]]&&/provinces_cn& &city_cn&&![CDATA[ 北京 ]]&&/city_cn& &address_cn&&![CDATA[ 北京 ]]&&/address_cn&&postcode&&![CDATA[ 100000 ]]&&/postcode& &tel&&![CDATA[ +86. ]]&&/tel& &fax&&![CDATA[ +86. ]]&&/fax& &email&&![CDATA[
]]&&/email& &/interface& 异常返回信息: &?xml version=&1.0& encoding=&utf-8& ?& &interface& &return_code&&![CDATA[ 433 ]]&&/return_code& &return_msg&&![CDATA[ 异常详细信息 ]]&&/return_msg& &/interface& 返回参数说明: return_code return_msg 返回状态代码,成功 = 200 返回详细提示信息 domain password 域名密码 buydate expiredate dns1 dns2域名注册日期 过期日期 主要 DNS 服务器 备用 DNS 服务器dom_cn fn_cn ln_cn country_cn provinces_cn city_cn address_cn域名所有者(中文) 姓(中文) 名(中文) 国家代码(中文) 中国 省份(中文) 城市(中文) 地址(中文)成都世纪东方网络通信有限公司 小 明四川 成都 成都市 XXXdom_en fn_en ln_en country_en provinces_en city_en address_en域名所有者(英文) 姓(英文) 名(英文) 国家代码(英文) CN 省份(英文) 城市(英文) 地址(英文)Oriental Century Xiao MingSichuan Chengdu Chengdu Citypostcode 邮政编码 tel 电话号码. fax email传真号码 电子邮件+86. 5、域名修改 DNS 接口 GET/POST 地址: http://www./api-product-domain-dns.html 参数: domain dns1 dns2 正常返回信息: &?xml version=&1.0& encoding=&utf-8& ?& &interface& &return_code&&![CDATA[ 200 ]]&&/return_code& &return_msg&&![CDATA[ 修改成功 ]]&&/return_msg& &/interface& 异常返回信息: &?xml version=&1.0& encoding=&utf-8& ?& &interface& &return_code&&![CDATA[ 433 ]]&&/return_code& &return_msg&&![CDATA[ 异常详细信息 ]]&&/return_msg& &/interface& 返回参数说明: return_code return_msg 返回状态代码,成功 = 200 返回详细提示信息 域名,如:
主要 DNS 服务器地址,如: 备用 DNS 服务器地址,如: 6、获取域名 Whois 信息接口 GET/POST 地址: http://www./api-product-domain-whois.html 参数: domain 正常返回信息: &?xml version=&1.0& encoding=&utf-8& ?& &interface& &return_code&&![CDATA[ 200 ]]&&/return_code& &return_msg&&![CDATA[ 验证通过 ]]&&/return_msg& 域名,如: &whois&&![CDATA[ Whois 信息 ]]&&/whois& &/interface& 异常返回信息: &?xml version=&1.0& encoding=&utf-8& ?& &interface& &return_code&&![CDATA[ 433 ]]&&/return_code& &return_msg&&![CDATA[ 异常详细信息 ]]&&/return_msg& &/interface& 返回参数说明: return_code return_msg 返回状态代码,成功 = 200 返回详细提示信息whoisWhois 信息 7、域名修改信息接口 GET/POST 地址: http://www./api-product-domain-info.html 参数: domain 域名,如: fn_cn ln_cn country_cn provinces_cn city_cn address_cn姓(中文) 名(中文) 国家代码(中文) 中国 省份(中文) 城市(中文) 地址(中文)小 明四川 成都 成都市 XXXfn_en ln_en country_en provinces_en city_en address_en姓(英文) 名(英文) 国家代码(英文) CN 省份(英文) 城市(英文) 地址(英文)Xiao MingSichuan Chengdu Chengdu Citypostcode 邮政编码 tel fax email 电话号码 传真号码 电子邮件. +86.
正常返回信息: &?xml version=&1.0& encoding=&utf-8& ?& &interface& &return_code&&![CDATA[ 200 ]]&&/return_code& &return_msg&&![CDATA[ 操作成功 ]]&&/return_msg& &/interface& 异常返回信息: &?xml version=&1.0& encoding=&utf-8& ?& &interface& &return_code&&![CDATA[ 433 ]]&&/return_code& &return_msg&&![CDATA[ 异常详细信息 ]]&&/return_msg& &/interface& 返回参数说明: return_code return_msg 返回状态代码,成功 = 200 返回详细提示信息========================================================================== ASP 例子: &% Set xmlhttp = Server.CreateObject(&WinHttp.WinHttpRequest.5.1&) Set xmldom = Server.CreateObject(&Microsoft.XMLDOM&) xmldom.Async = False xmlhttp.SetTimeouts , xmlhttp.open &GET&,&http://www./api-get-time.html&,false xmlhttp.send xmldom.LoadXML(xmlhttp.responseText) Set root = xmldom.documentElement for i = 0 to root.childNodes.length - 1 list = ucase(root.childNodes(i).nodeName) if list = &TIME& then strTime = root.childNodes(i).text end if Nextresponse.write strTime %&Web Service 的工作原理Web Service 基本概念Web Service 也叫 XML Web Service WebService 是一种可以接收从 Internet 或者 Intranet 上的其它系统中传递过 来的请求,轻量级的独立的通讯技术。是:通过 SOAP 在 Web 上提供的软件服务,使用 WSDL 文件进行说明,并 通过 UDDI 进行注册。XML:(Extensible Markup Language)扩展型可标记语言。面向短期的临时数据处理、面向万维网络,是 Soap 的 基础。Soap:(Simple Object Access Protocol)简单对象存取协议。是 XML Web Service 的通信协议。当用户通过 UDDI 找到你的 WSDL 描述文档后,他通过可以 SOAP 调用你建立的 Web 服务中的一个或多个操作。SOAP 是 XML 文 档形式的 调用方法的规范,它可以支持不同的底层接口,像 HTTP(S)或者 SMTP。 WSDL:(Web Services Description Language) WSDL 文件是一个 XML 文档,用于说明一组 SOAP 消息以及如 何交换这些消息。大多数情况下由软件自动生成和使用。UDDI (Universal Description, Discovery, and Integration) 是一个主要针对 Web 服务供应商和使用者的新项目。在 用户能够调用 Web 服务之前,必须确定这个服务内包含哪些商务方法,找到被调用的接口定义,还要在服 务端来 编制软件,UDDI 是一种根据描述文档来引导系统查找相应服务的机制。UDDI 利用 SOAP 消息机制(标准的 XML/HTTP)来发布,编辑,浏览 以及查找注册信息。它采用 XML 格式来封装各种不同类型的数据,并且发送到 注册中心或者由注册中心来返回需要的数据。调用原理:Web 服务有两层含义:1、是指封装成单个实体并发布到网络上的功能集合体;2、是指功能集合体被调用后所提供 的服务。简单地讲,Web 服务是一个 URL 资源,客户端可以通过编程方式请求得到它的服务,而不需要知道所请 求的服务是怎样实现的,这一点与传统的分布式组件对象模型不同。Web 服务的体系结构是基于 Web 服务提供者、Web 服务请求者、Web 服务中介者三个角色和发布、发现、绑定三 个动作构建的。简单地说,Web 服务提供者就是 Web 服务的拥有者,它耐心等待为其他服务和用户提供自己已有 的功能;Web 服务请求者就是 Web 服务功能的使用者,它利用 SOAP 消息向 Web 服务提供者发送请求以获得服 务;Web 服务中介者的作用是把一个 Web 服务请求者与合适的 Web 服务提供者联系在一起, 它充当管理者的角色, 一般是 UDDI。这三个角色是根据逻辑关系划分的,在实际应用中,角色之间很可能有交叉:一个 Web 服务既可以 是 Web 服务提供者,也可以是 Web 服务请求者,或者二者兼而有之。显示了 Web 服务角色之间的关系:其中,“发 布”是为了让用户或其他服务知道某个 Web 服务的存在和相关信息;“查找(发现)”是为了找到合适的 Web 服务;“绑 定”则是在提供者与请求者之间建立某种联系。 图 2-1 Web service 的体系结构实现一个完整的 Web 服务包括以下步骤:◆ Web 服务提供者设计实现 Web 服务,并将调试正确后的 Web 服务通过 Web 服务中介者发布,并在 UDDI 注册 中心注册; (发布)◆ Web 服务请求者向 Web 服务中介者请求特定的服务,中介者根据请求查询 UDDI 注册中心,为请求者寻找满足 请求的服务; (发现)◆ Web 服务中介者向 Web 服务请求者返回满足条件的 Web 服务描述信息,该描述信息用 WSDL 写成,各种支持 Web 服务的机器都能阅读;(发现)◆ 利用从 Web 服务中介者返回的描述信息生成相应的 SOAP 消息,发送给 Web 服务提供者,以实现 Web 服务的 调用;(绑定)◆ Web 服务提供者按 SOAP 消息执行相应的 Web 服务,并将服务结果返回给 Web 服务请求者。(绑定)调用方式:1. Net 下采用 GET/POST/SOAP 方式动态调用 WebService 的简易灵活方法(C#)webservice 的调用有 3 种方式 1). httpget 2). httppost 3). httpsoapsoap 的优点是 可以传递结构化的 数据,而前两种不行。 btw, soap 最终也是使用 HTTP 传送 XM安全:Webservice 为作为方便的服务被用广大领域使用的同时,也成为了黑客们的美食。在这里,本文将就目前对 Webservice 安全所能做的改进做简单介绍。在 Webservice 中的安全主要分为以下三个方面。传输SSL/HTTPS 对连接加密,而不是传输数据消息数据加密(XML Encryption)数字签名(XML-DSIG)底层架构 利用应用服务安全机制传输时的安全是最容易被加入到你的 Webservice 应用中的,利用现有的 SSL 和 HTTPS 协议,就可以很容易的获 得连接过程中的安全。然 而这种安全实现方法有两个弱点。 一是它只能保证数据传输的安全, 而不是数据本身的安全, 数据一旦到达某地, 那么就可以被任何人所查看。而在 Webservice 中,一份数据可能到达多个地方,而这份数据却不该被所有的接受 者所查看。二是它提供的是要么全有要么全无的保护,你不能选择哪部分数 据要被保护,而这种可选择性也是在 Webservice 中所常要用到的。 第二层的保护是对于消息本身的保护。你可以使用已有的 XML 安 全扩展标准,实现数字签名的功能,从而保证你 的消息是来自特定方并没有被修改过。XML 文件的加密技术从更大程度上加强了 Webservice 的安全,它 能够定 制数据传输到后,能否被接受者所查看,进一步完善了传输后的安全,业界也在不断的制定 Webservice 的安全标 准,比如 SAML 和 WS-Security。最后一层保护就是依靠底层架构的安全,这更多的来自于操作系统和某些中间件的保护。比如在 J2EE 中,主持 Webservice 的应用服务器。目前很多的 J2EE 应用服务器都支持 Java Authentication and Authorization Service (JAAS),这是最近被加入到 J2SE 1.4 当中的。利用主持 Webservice 的服务器,实现一些安全机制这是很自然的做 法。另一种利用底层架构的安全方法就是,做一个独立的负责安全的服 务器,Webservice 的使用者和创建者都需 要与之取得安全信任。特点:Web Service 的主要目标是跨平台的可互操作性。为了实现这一目标,Web Service 完全基于 XML(可扩展标记语 言)、XSD(XML Schema)等独立于平台、独立于软件供应商的标准,是创建可互操作的、分布式应用程序的新 平台。因此使用 Web Service 有许多优点:1、跨防火墙的通信如果应用程序有成千上万的用户,而且分布在世界各地,那么客户端和服务器之间的通信将是一个棘手的问题。因 为客户端和服务器之间通常会有防火墙或者 代理服务器。传统的做法是,选择用浏览器作为客户端,写下一大堆 ASP 页面,把应用程序的中间层暴露给最终用户。这样做的结果是开发难度大,程序很难维 护。 要是客户端代码 不再如此依赖于 HTML 表单,客户端的编程就简单多了。如果中间层组件换成 Web Service 的话,就可以从用户界 面直接调用中间层组件,从而省掉建立 ASP 页面的那一步。要调用 Web Service,可以直接使用 Microsoft SOAP Toolkit 或.net 这样的 SOAP 客户端,也可以使用自己开发的 SOAP 客户端,然后把它和应用程序连接起来。不仅 缩短了开发周期,还减少了代码复 杂度,并能够增强应用程序的可维护性。同时,应用程序也不再需要在每次调用 中间层组件时,都跳转到相应的&结果页&。2、应用程序集成企业级的应用程序开发者都知道,企业里经常都要把用不同语言写成的、在不同平台上运行的各种程序集成起来, 而这种集成将花费很大的开发力量。 应用程 序经常需要从运行的一台主机上的程序中获取数据; 或者把数据发送到 主机或其它平台应用程序中去。即使在同一个平台上,不同软件厂商生产的各种软件也常常需 要集成起来。通过 Web Service,应用程序可以用标准的方法把功能和数据&暴露&出来,供其它应用程序使用。XML Web services 提供了在松耦合环境中使用标准协议(HTTP、XML、SOAP 和 WSDL)交换消息的能力。消 息可以是结构化的、带类型的,也可以是松散定义的。3、B2B 的集成B2B 指的是 Business to Business,as in businesses doing business with other businesses,商家(泛指企业)对商家 的电子商务, 即企业与企业之间通过互联网进行产品、 服务及信息的交换。 通俗的说法是指进行电子商务交易的供 需 双方都是商家(或企业、公司),她们使用了 Internet 的技术或各种商务网络平台,完成商务交易的过程。Web Service 是 B2B 集成成功的关键。通过 Web Service,公司可以只需把关键的商务应用&暴露&给指定的供应商 和客户,就可以了,Web Service 运行在 Internet 上,在世界任何地方都可轻易实现,其运行成本就相对较低。Web Service 只是 B2B 集成的一个关键部分,还需要许多其它的部分才能实现集成。 用 Web Service 来实现 B2B 集成 的最大好处在于可以轻易实现互操作性。只要把商务逻辑&暴露&出来,成为 Web Service,就可以让任何指定的合 作伙伴调用这些商务逻辑,而不管他们的系统在什么平台上运行,使用什么开发语言。这样就大大减少了花在 B2B 集成上 的时间和成本。4、软件和数据重用 Web Service 在允许重用代码的同时,可以重用代码背后的数据。使用 Web Service,再也不必像以前那样,要先 从第三方购买、安装软件组件,再从应用程序中调用这些组件;只需要直接调用远端的 Web Service 就可以了。另 一种软件重用的情况是,把好几个应用程序的功能集成起来,通过 Web Service &暴露&出来,就可以非常容易地把 所有这些功能都集成到你的门户站点中,为用户提供一个统一的、友好的界面。 可以在应用程序中使用第三方的 Web Service 提供的功能,也可以把自己的应用程序功能通过 Web Service 提供给别人。两种情况下,都可以重 用代码和代码背后的数据。从以上论述可以看出,Web Service 在通过 Web 进行互操作或远程调用的时候是最有用的。不过,也有一些情况, Web Service 根本不能带来任何好处,Web Service 有一下缺点:1、 单机应用程序目前,企业和个人还使用着很多桌面应用程序。其中一些只需要与本机上的其它程序通信。在这种情况下,最好就 不要用 Web Service,只要用本地的 API 就可以了。COM 非常适合于在这种情况下工作,因为它既小又快。运行 在同一台服务器上的服务器软件也是这样。当然 Web Service 也能用在这些场合,但那样不仅消耗太大,而且不 会带来任何好处。2、 局域网的一些应用程序在许多应用中,所有的程序都是在 Windows 平台下使用 COM,都运行在同一个局域网上。在这些程序里,使用 DCOM 会比 SOAP/HTTP 有效 得多。与此相类似,如果一个.net 程序要连接到局域网上的另一个.net 程序,应该 使用.net Remoting。其实在.net Remoting 中,也可以指定使用 SOAP/HTTP 来进行 Web Service 调用。不过最好 还是直接通过 TCP 进行 RPC 调用,那样会有效得多。1.3、XML Web Service 的应用1.最初的 XML Web Service 通常是可以方便地并入应用程序的信息来源,如股票价格、天气预报、体育成绩等等。 2.以 XML Web Service 方式提供现有应用程序, 可以构建新的、 更强大的应用程序, 并利用 XML Web Service 作 为构造块。例如,用户可以开发一个采购应用程序,以自动获取来自不同供应商的价格信息,从而使用户可以选择供应商,提 交订单,然后跟踪货物的运输,直至收到货 物。而供应商的应用程序除了在 Web 上提供服务外,还可以使用 XML Web Service 检查客户的信用、收取货款,并与货运公司办理货运手续。SOAP 消息格式:1 &?xml version=&1.0&?& 2 &soap:Envelope 3 xmlns:soap=&http://www.w3.org/2001/12/soap-envelope& 4 soap:encodingStyle=&http://www.w3.org/2001/12/soap-encoding& 5 & 6 7 &soap:Header& 8 9 1 &m:Trans xmlns:m=&/transaction/& soap:mustUnderstand=&1&&234 &/m:Trans&0 &/soap:Header& 1 1 1 &soap:Body& 2 1 &m:GetPrice xmlns:m=&/prices&& &m:Item&Apples&/m:Item& 3&/m:GetPrice&1 &/soap:Body& 4 &/soap:Envelope& 1 5 1 6 1 7 1 8RESTful API 设计最佳实践数据模型已经稳定,接下来你可能需要为 web(网站)应用创建一个公开的 API(应用程序编程接口)。需要认识 到这样一个问题:一旦 API 发布后, 就很难对它做很大的改动并且保持像先前一样的正确性。现在,网络上有很 多关于 API 设计的思路。但是在全部案例中没有一种被广泛采纳的标准,有很多的选 择:你接受什么样的格式? 如何认证?API 应该被版本化吗?在为 SupportFu(一个轻量级的 Zendesk 替换实现)设计 API 时,对于这些问题我尽量得出一些务实的答案。我的 目标是设计这样一个 API,它容易使用和采纳,足够灵活去为我们用户接口去埋单。API 的关键要求 许多网上能找到的 API 设计观点都是些学术讨论,这些讨论是关于模糊标准的主观解释,而不是关于在现实世界中 具有意义的事。本文中我的目标是,描述一下为当今的 web 应用而设计的实用的 API 的最佳实践。如果感觉不对, 我不会去尝试满足某个标准。为了帮助进行决策,我已经写下了 API 必须力争满足的一些要求:? 它应当在需要的地方使用 web 标准 ? 它应当对开发者友好并且便于在浏览器地址栏中浏览和探索 ? 它应当是简单、直观和一致的,使它用起来方便和舒适 ? 它应当提供足够的灵活性来增强大多数的 SupportFu 用户界面 ? 它应当是高效的,同时要维持和其他需求之间的平衡一个 API 是一个开发者的 UI - 就像其他任何 UI 一样, 确保用户体验被认真的考虑过是很重要的!使用 RESTful URLs and actions如果有一样东西获得广泛认可的话,那就是 RESTful 原则。Roy Felding 在他论文 network based software architectures 的 第五章 中首次介绍了这些原则。这些 REST 的关键原则与将你的 API 分割成逻辑资源紧密相关。使用 HTTP 请求控制这些资源,其中,这些方法 (GET, POST, PUT, PATCH, DELETE)具有特殊含义。可是我该整出什么样的资源呢?好吧,它们应该是有意义于 API 使用者的名词(不是动词)。虽然内部 Model 可 以简单地映射到资源上,但那不一定是个一对一的映射。这里的关键是不要泄漏与 API 不相关的实现细节。一些相 关的名词可以是票,用户和小组。一旦定义好了资源, 需要确定什么样的 actions 应用它们,这些 actions 怎么映射到你的 API 上。RESTful 原则 提供了 HTTP methods 映射作为策略来处理 CRUD actions,如下: ? ? ? ? ? ?GET /tickets - 获取 tickets 列表 GET /tickets/12 - 获取一个单独的 ticket POST /tickets - 创建一个新的 ticket PUT /tickets/12 - 更新 ticket #12 PATCH /tickets/12 - 部分更新 ticket #12 DELETE /tickets/12 - 删除 ticket #12REST 非常棒的是,利用现有的 HTTP 方法在单个的 /tickets 接入点上实现了显著的功能。没有什么方法命名约 定需要去遵循,URL 结构是整洁干净的。 REST 太棒了!接入点的名称应该选择单数还是复数呢?keep-it-simple 原则可以在此应用。虽然你内在的语法知识会 告诉你用复 数形式描述单一资源实例是错误的,但实用主义的答案是保持 URL 格式一致并且始终使用复数形式。不用处理各 种奇形怪状的复数形式(比如 person/people,goose/geese)可以让 API 消费者的生活更加美好,也让 API 提供 者更容易实现 API(因为大多数现代框架天然地 将/tickets 和/tickets/12 放在同一个控制器下处理)。但是你该如何处理(资源的)关系呢?如果关系依托于另外一个资源,Restful 原则提供了很好的指导原则。让我们 来看一个例子。SupportFu 的一个 ticket 包含许多消息(message)。这些消息逻辑上与/tickets 接入点的映射关系 如下:? ? ? ? ? ?GET /tickets/12/messages - 获取 ticket #12 下的消息列表 GET /tickets/12/messages/5 - 获取 ticket #12 下的编号为 5 的消息 POST /tickets/12/messages - 为 ticket #12 创建一个新消息 PUT /tickets/12/messages/5 - 更新 ticket #12 下的编号为 5 的消息 PATCH /tickets/12/messages/5 - 部分更新 ticket #12 下的编号为 5 的消息 DELETE /tickets/12/messages/5 - 删除 ticket #12 下的编号为 5 的消息 或者如果某种关系不依赖于资源,那么在资源的输出表示中只包含一个标识符是有意义的。API 消费者然后除了请 求资源所在的接入点外,还得再请求一次 关系所在的接入点。但是如果一般情况关系和资源一起被请求,API 可以 提供自动嵌套关系表示到资源表示中,这样可以防止两次请求 API。如果 Action 不符合 CRUD 操作那该怎么办?这是一个可能让人感到模糊不解的地方。有几种处理方法:1. 重新构造这个 Action,使得它像一个资源的 field(我理解为部分域或者部分字段)。这种方法在 Action 不包含参数的情况下可以奏效。例如一个有效的 action 可以映射成布尔类型 field,并且可以通过 PATCH 更 新资源。2. 利用 RESTful 原则像处理子资源一样处理它。例如,Github 的 API 让你通过 PUT /gists/:id/star 来 star agist ,而通过 DELETE /gists/:id/star 来进行 unstar 。3. 有时候你实在是没有办法将 Action 映射到任何有意义的 RESTful 结构。例如,多资源搜索没办法真正地映射到任何 一个资源接入点。 这种情况, /search 将非常有意义, 虽然它不是一个名词。 这样做没有问题 - 你 只需要从 API 消费者的角度做正确的事, 并确保所做的一切都用文档清晰记录下来了以避免 (API 消费者的) 困惑。总是使用 SSH总是使用 SSL,没有例外。今天,您的 web api 可以从任何地方访问互联网(如图书馆、咖啡店、机场等)。不是所 有这些都是安全的,许多不加密通信,便于窃听或伪造,如果身份验证凭证被劫持。另一个优点是,保证总是使用 SSL 加密通信简化了认证效果――你可以摆脱简单的访问令牌,而不是让每个 API 请求 签署。 要注意的一点是非 SSL 访问 API URLs。不要重定向这些到对应的 SSL。相反,抛出一个系统错误!最后一件你想要 的是配置不佳的客户发送请求到一个未加密的端点,只是默默地重定向到实际加密的端点文档API 的好坏关键看其文档的好坏. 好的 API 的说明文档应该很容易就被找到,并能公开访问。在尝试任何整合工作 前大部分开发者会先查看其文档。 当文档被藏于一个 PDF 之中或要求必须登记信息时, 将很难被找到也很难搜索到。好的文档须提供从请求到响应整个循环的示例。最好的是,请求应该是可粘贴的例子,要么是可以贴到浏览器的链 接,要么是可以贴到终端里的 curl 示例 。 GitHub 和 Stripe 在这方面做的非常出色。一旦你发布一个公开的 API,你必须承诺&在没有通告的前提下,不会更改 APIDe 功能& .对于外部可见 API 的更新, 文档必须包含任何将废弃的 API 的时间表和详情。应该通过博客(更新日志)或者邮件列表送达更新说明(最好两者都 通知)。版本控制必须对 API 进行版本控制。版本控制可以快速迭代并避免无效的请求访问已更新的接入点。它也有助于帮助平滑过 渡任何大范围的 API 版本变迁,这样就可以继续支持旧版本 API。关于 API 的版本是否应该包含在 URL 或者请求头中 莫衷一是。从学术派的角度来讲,它应该出现在请求头中。然 而版本信息出现在 URL 中必须保证不同版本资源的浏览器可浏览性(browser explorability),还记得文章开始提 到的 API 要求吗?我非常赞成 approach that Stripe has taken to API versioning - URL 包含一个主版本号(比如 http://shonzilla/api/v1/customers/1234) ), 但是 API 还包含基于日期的子版本(比如 http://shonzilla/api/v1.2/customers/1234),可以通过配置 HTTP 请 求头来进行选择。 这种情况下, 主版本确保 API 结构总体稳定性, 而子版本会考虑细微的变化 (field deprecation、 接入点变化等)。API 不可能完全稳定。 变更不可避免, 重要的是变更是如何被控制的。 维护良好的文档、 公布未来数月的 deprecation 计划,这些对于很多 API 来说都是一些可行的举措。它归根结底是看对于业界和 API 的潜在消费者是否合理。结果过滤,排序和搜索最好是尽量保持基本资源 URL 的简洁性。 复杂结果过滤器、排序需求和高级搜索 (当限定在单一类型的资源时) , 都能够作为在基本 URL 之上的查询参数来轻松实现。下面让我们更详细的看一下:过滤: 对每一个字段使用一个唯一查询参数,就可以实现过滤。 例如,当通过“/tickets”终端来请求一个票据列表时, 你可能想要限定只要那些在售的票。这可以通过一个像 GET /tickets?state=open 这样的请求来实现。这里“state” 是一个实现了过滤功能的查询参数。排序: 跟过滤类似, 一个泛型参数排序可以被用来描述排序的规则. 为适应复杂排序需求, 让排序参数采取逗号分隔 的字段列表的形式,每一个字段前都可能有一个负号来表示按降序排序。我们看几个例子:? ?GET /tickets?sort=-priority - 获取票据列表,按优先级字段降序排序 GET /tickets?sort=-priority,created_at - 获取票据列表,按“priority”字段降序排序。在一个特定的优先级内, 较早的票排在前面。搜索: 有时基本的过滤不能满足需求,这时你就需要全文检索的力量。或许你已经在使用 ElasticSearch 或者其它 基于 Lucene 的搜索技术。当全文检索被用作获取某种特定资源的资源实例的机制时, 它可以被暴露在 API 中,作 为资源终端的查询参数,我们叫它“q”。搜索类查询应当被直接交给搜索引擎,并且 API 的产出物应当具有同样的格 式,以一个普通列表作为结果。把这些组合在一起,我们可以创建以下一些查询:? ? ?GET /tickets?sort=-updated_at - 获取最近更新的票 GET /tickets?state=closed&sort=-updated_at - 获取最近更新并且状态为关闭的票。 GET /tickets?q=return&state=open&sort=-priority,created_at - 获取优先级最高、最先创建的、状态为开放 的票,并且票上有 'return' 字样。一般查询的别名为了使普通用户的 API 使用体验更加愉快, 考虑把条件集合包装进容易访问的 RESTful 路径中。比如上面的,最 近关闭的票的查询可以被包装成 GET /tickets/recently_closed限制哪些字段由 API 返回API 的使用者并不总是需要一个资源的完整表示。选择返回字段的功能由来已久,它使得 API 使用者能够最小化网 络阻塞,并加速他们对 API 的调用。使用一个字段查询参数,它包含一个用逗号隔开的字段列表。例如,下列请求获得的信息将刚刚足够展示一个在售 票的有序列表:GET /tickets?fields=id,subject,customer_name,updated_at&state=open&sort=-updated_at更新和创建应该返回一个资源描述 一个 PUT, POST 或者 PATCH 调用可能会对指定资源的某些字段造成更改,而这些字段本不在提供的参数之列 (例如: created_at 或 updated_at 这两个时间戳)。 为了防止 API 使用者为了获取更新后的资源而再次调用该 API, 应当使 API 把更新(或创建)后的资源作为 response 的一部分来返回。以一个产生创建活动的 POST 操作为例, 使用一个 HTTP 201 状态代码 然后包含一个 Location header 来指向新 生资源的 URL。你是否应该 HATEOAS?(译注:Hypermedia as the Engine of Application State (HATEOAS)超媒体作为应用程序状态引擎)对于 API 消费方是否应该创建链接,或者是否应该将链接提供给 API,有许多混杂的观点。RESTful 的设计原则指 定了 HATEOAS ,大致说明了与某个端点的交互应该定义在元数据(metadata)之中,这个元数据与输出结果一同到 达,并不基于其他地方的信息。虽然 web 逐渐依照 HATEOAS 类型的原则运作(我们打开一个网站首页并随着我们看到的页面中的链接浏览), 我不认为我们已经准备好 API 的 HATEOAS 了。当浏览一个网站的时候,决定点击哪个链接是运行时做出的。然 而, 对于 API, 决定哪个请求被发送是在写 API 集成代码时做出的, 并不是 运行时。 这个决定可以移交到运行时吗? 当然可以,不过顺着这条路没有太多好处,因为代码仍然不能不中断的处理重大的 API 变化。也就是说,我认为 HATEOAS 做出了承诺,但是还没有准备好迎接它的黄金时间。为了完全实现它的潜能,需要付出更多的努力去定 义围绕着这些原则的标准和工具。目前而言,最好假定用户已经访问过输出结果中的文档&包含资源标识符,而这些 API 消费方会在制作链接的时候 用到。关注标识符有几个优势――网络中的数据流减少了,API 消费方存储的数据也减少了(因为它们存储的是小 的标识符而不是包含标识符的 URLs)。同样的,在 URL 中提供本文倡导的版本号,对于在一个很长时间内 API 消费方存储资源标识符(而不是 URLs), 它更有意义。总之,标识符相对版本是稳定的,但是表示这一点的 URL 却不是的!只返回 JSON是时候在 API 中丢弃 XML 了。XML 冗长,难以解析,很难读,他的数据模型和大部分编程语言的数据模型 不兼容, 而他的可扩展性优势在你的主要需求是必须序列化一个内部数据进行输出展示时变得不相干。我不打算对上述进行解释了,貌似诸如 (YouTube, Twitter 和 Box)之类的已经开始了去 XML 化.给你一张 google 趋势图,比较 XML API 和 JSON API 的,供你参考:但是,如果你的客户群包括大量的企业客户,你会发现自己不得不支持 XML 的方式。如果你必须这样,一个新问题出 现了:媒体类型是应该基于 Accept 头还是基于 URL 呢 ? 为确保浏览器的浏览性,应该基于 URL。这里最明智的选择是 在端点 URL 后面附加 .json 或 .xml 的扩展.字段名称书写格式的 snake_case vs camelCase 如果你在使用 JSON (JavaScript Object Notation) 作为你的主要表示格式, 正确的方法就是遵守 JavaScript 命名约 定――对字段名称使用 camelCase!如果你要走用各种语言建设客户端库的路 线,最好使用它们惯用的命名约定 ―― C# & Java 使用 camelCase, python & ruby 使用 snake_case。深思:我一直认为 snake_case 比 JavaScript 的 camelCase 约定更容易阅读。我没有任何证据来支持我的直觉,直 到现在,基于从 2010 年的 camelCase 和 snake_case 的眼动追踪研究 (PDF),snake_case 比驼峰更容易阅读 20%!这种阅读上的影响会影响 API 的可勘探性和文档中的示例。许多流行的 JSON API 使用 snake_case。我怀疑这是由于序列化库遵从它们所使用的底层语言的命名约定。也许 我们需要有 JSON 序列库来处理命名约定转换。缺省情况下确保漂亮的打印和支持 gzip一个提供空白符压缩输出的 API,从浏览器中查看结果并不美观。虽然一些有序的查询参数(如 ?pretty=true )可 以提供来使漂亮打印生效,一个默认情况下能进行漂亮打印的 API 更为平易近人。额外数据传输的成本是微不足道 的,尤其是当你比较不执行 gzip 压缩的 成本。考虑一些用例: 假设分析一个 API 消费者正在调试并且有自己的代码来打印出从 API 收到的数据――默认情况下这 应是可读的。或者,如果消费者抓住他 们的代码生成的 URL,并直接从浏览器访问它――默认情况下这应是可读 的。这些都是小事情。做好小事情会使一个 API 能被更愉快地使用!那么该如何处理额外传输的数据呢? 让我们看一个实际例子。我从 GitHub API 上拉取了一些数据,默认这些数据使用了漂亮打印(pretty print)。我也 将做一些 GZIP 压缩后的对比。$ curl /users/veesahni & 1 with-whitespace.txt $ ruby -r json -e 'puts JSON JSON.parse(STDIN.read)' & with-whitespace.txt & 2 without-whitespace.txt $ gzip -c with-whitespace.txt & 3 with-whitespace.txt.gz $ gzip -c without-whitespace.txt ? 4 without-whitespace.txt.gz输出文件的大小如下:? ? ? ?without-whitespace.txt - 1252 bytes with-whitespace.txt - 1369 bytes without-whitespace.txt.gz - 496 bytes with-whitespace.txt.gz - 509 bytes在这个例子中,当未启用 GZIP 压缩时空格增加了 8.5%的额外输出大小,而当启用 GZIP 压缩时这个比例是 2.6%。 另一方面,GZIP 压缩节省了 60%的带宽。由于漂亮打印的代价相对比较小,最好默认使用漂亮打印,并确保 GZIP 压缩被支持。关于这点想了解更多的话, Twitter 发现当对他们的 Streaming API 开启 GZIP 支持后可以在某些情况获得 80%的带 宽节省 。Stack Exchange 甚至强制要求必须对 API 请求结果使用 GZIP 压缩(never return a response that's not compressed)。 不要默认使用大括号封装,但要在需要的时候支持许多 API 会像下面这样包裹他们的响应信息:1{ &data& : 2 { &id& : 3 123, &name& : &John 4 &5 } 6}有不少这样做的理由 - 更容易附加元数据或者分页信息,一些 REST 客户端不允许轻易的访问 HTTP 头信息,并 且 JSONP 请求不能访问 HTTP 头信息。无论怎样,随着迅速被采用的标准,比如 CORS 和 Link header from RFC 5988, 大括号封装开始变得不必要。我们应当默认不使用大括号封装,而仅在特殊情况下使用它,从而使我们的 API 面向未来。特殊情况下该如何使用大括号封装? 有两种情况确实需要大括号封装 - 当 API 需要通过 JSONP 来支持跨域的请求时, 或者当客户端没有能力处理 HTTP 头信息时。JSONP 请求附带有一个额外的查询参数(通常称为 callback 或 jsonp) 表示了回调函数的名称。如果提供了这个参 数,API 应当切换至完整封装模式,这时它总是用 200HTTP 状态码作为响应,然后把真实的状态码放入 JSON 有 效载荷中。任何被一并添加进响应中的额外的 HTTP 头信息都应当被映射到 JSON 字段中, 像这样:callback_function 1 ({ status_code: 2 200, next_page: &https://.. 3 &, response: 4 { ... actual JSON response 5 body ...6 } } 7 )类似的,为了支持 HTTP 受限的客户端,可以允许一个特殊的查询参数“?envelope=true”来触发完整封装(没有 JSONP 回调函数)。 使用 JSON 编码的 POST, PUT & PATCH 请求体如果你正在跟随本文中讲述的开发过程,那么你肯定已经接受 JSON 作为 API 的输出。下面让我们考虑使用 JSON 作为 API 的输入。许多 API 在他们的 API 请求体中使用 URL 编码。URL 编码正如它们听起来那样 - 将使用和编码 URL 查询参数时 一样的约定,对请求体中的键值对进行编码。这很简单,被广泛支持而且实用。然而,有几个问题使得 URL 编码不太好用。首先,它没有数据类型的概念。这迫使 API 从字符串中转换整数和布 尔值。而且,它并没有真正的层次结构的 概念。尽管有一些约定,可以用键值对构造出一些结构(比如给一个键增 加“[]”来表示一个数组),但还是不能跟 JSON 原生的层次结构相比。如果 API 很简单,URL 编码可以满足需要。然而,复杂 API 应当严格对待他们的 JSON 格式的输入。不论哪种方 式,选定一个并且整套 API 要保持一致。一个能接受 JSON 编码的 POST, PUT 和 PATCH 请求的 API,应当也需要把 Content-Type 头信息设置为 application/json,或者抛出一个 415 不支持的媒体类型(Unsupported Media Type)的 HTTP 状态码。分页信封喜欢将分页信息包含在信封自身的 API。我不能指责这点――直到最近,我们才找到更好的方法。正确的方法 是使用 RFC 5988 中介绍的链接标头。使用链接标头的 API 可以返回一系列线程的链接,API 使用者无需自行生成链接。这在分页时指针导向 非常重要。 下面是抓取自 Github 的正确使用链接标头的文件: Link: &/user/repos?page=3&per_page=100&; rel=&next&, &/user/repos?page=50&per_page=100&; rel=&last&不过这个并非完成版本,因为很多 API 喜欢返回额外信息,例如可用结果的总数。需要发送数量的 API 可用类 似 X-Total-Count 的普通 HTTP 标头。自动装载相关的资源描述在很多种情况下,API 的使用者需要加载和被请求资源相关的数据(或被请求资源引用的数据)。与要求使用者反 复访问 API 来获取这些信息相比, 允许在请求原始资源的同时一并返回和装载相关资源, 将会带来明显的效率提升。然而, 由于这样确实 有悖于一些 RESTful 原则, 所以我们可以只使用一个内置的(或扩展)的查询参数来实现这一 功能,来最小化与原则的背离。这种情况下,“embed”将是一个逗号隔开的需要被内置的字段列表。点号可以用来表示子字段。例如:GET /ticket/12?embed=customer.name,assigned_user这将返回一个附带有详细内置信息的票据,如下:0 { 1 0 &id& :2 12, 0 &subject& : &I have a3 question!&, 0 &summary& : &Hi, .... 4 &, 0 5 { 0 6 & 0 7 , 0 8 { 0 &id& : assigned_user: } &name& : &Bob &customer& :9 42, 1 0 &, 1 1 } 1 } 2 &name& : &Jim当然,实现类似于这种功能的能力完全依赖于内在的复杂度。这种内置的做法很容易产生 N+1 select 问题。重写/覆盖HTTP 方法 一些 HTTP 客户端仅能处理简单的的 GET 和 POST 请求,为照顾这些功能有限的客户端,API 需要一种方式来重 写 HTTP 方法. 尽管没有一些硬性标准来做这事,但流行的惯例是接受一种叫 X-HTTP 的请求头,重写是用一个字 符串值包含 PUT,PATCH 或 DELETE 中的一个。注意重写头应当仅接受 POST 请求,GET 请求绝不应该 更改服务器上的数据!速率限制为了防止滥用, 标准的做法是给 API 增加某种类型的速率限制。 RFC 6585 中介绍了一个 HTTP 状态码 429 请求过 多来实现这一点。不论怎样,在用户实际受到限制之前告知他们限制的存在是很有用的。这是一个现在还缺乏标准的领域,但是已经 有了一些流行的使用 HTTP 响应头信息的惯用方法。最少时包含下列头信息(使用 Twitter 的命名约定 来作为头信息,通常没有中间词的大写):? ? ?X-Rate-Limit-Limit - 当期允许请求的次数 X-Rate-Limit-Remaining - 当期剩余的请求次数 X-Rate-Limit-Reset - 当期剩余的秒数为什么对 X-Rate-Limit-Reset 不使用时间戳而使用秒数?一个时间戳包含了各种各样的信息,比如日期和时区,但它们却不是必需的。一个 API 使用者其实只是想知道什么 时候能再次发起请求,对他们来说一个秒数用最小的额外处理回答了这个问题。同时规避了时钟偏差的问题。有些 API 给 X-Rate-Limit-Reset 使用 UNIX 时间戳(纪元以来的秒数)。不要这样做!为什么对 X-Rate-Limit-Reset 使用 UNIX 时间戳是不好的做法? HTTP 规范已经指定使用 RFC 1123 的日期格式 (目前被使用在日期, If-Modified-Since & Last-Modified HTTP 头 信息中)。如果我们打算指定一种使用某种形式时间戳的、新的 HTTP 头信息,我们应当遵循 RFC 1123 规定,而 不是使用 UNIX 时间戳。认证一个 RESTful API 应当是无状态的。这意味着认证请求应当不依赖于 cookie 或 session。相反,每一个请求都应 当携带某种类型的认证凭证。由于总是使用 SSL,认证凭证能够被简化为一个随机产生的访问令牌,里面传入一个使用 HTTP Basic Auth 的用户 名字段。这样做的极大的好处是,它是完全的浏览器可探测的 - 如果浏览器从服务器收到一个 401 未授权状态码, 它仅需要一个弹出框来索要凭证即可。然而,这种基于基本认证的令牌的认证方法,仅在满足下列情形时才可用,即用户可以把令牌从一个管理接口复制 到 API 使用者环境。当这种情形不能成立时,应当使用 OAuth 2 来产生安全令牌并传递给第三方。OAuth 2 使用了 承载令牌(Bearer tokens) 并且依赖于 SSL 的底层传输加密。一个需要支持 JSONP 的 API 将需要第三种认证方法, 因为 JSONP 请求不能发送 HTTP 基本认证凭据(HTTP Basic Auth)或承载令牌(Bearer tokens) 。这种情况下,可以使用一个特殊的查询参数 access_token。注意,使用查询参 数 token 存在着一个固有的安全问题,即大多数的 web 服务器都会把查询参数记录到服务日志中。这是值得的,所有上面三种方法都只是跨 API 边界两端的传递令牌的方式。实际的底层令牌本身可能都是相同的。缓存 HTTP 提供了一套内置的缓存框架! 所有你必须做的是,包含一些额外的出站响应头信息,并且在收到一些入站请 求头信息时做一点儿校验工作。有两种方式: ETag 和 Last-ModifiedETag: 当产生一个请求时, 包含一个 HTTP 头,ETag 会在里面置入一个和表达内容对应的哈希值或校验值。这个 值应当跟随表达内容的变化而变化。 现在, 如果一个入站 HTTP 请求包含了一个 If-None-Match 头和一个匹配的 ETag 值,API 应当返回一个 304 未修改状态码,而不是返回请求的资源。Last-Modified: 基本上像 ETag 那样工作, 不同的是它使用时间戳。 在响应头中, Last-Modified 包含了一个 RFC 1123 格式的时间戳,它使用 If-Modified-Since 来进行验证。注意,HTTP 规范已经有了 3 种不同的可接受的日期格式 , 服务器应当准备好接收其中的任何一种。错误就像一个 HTML 错误页面给访问者展示了有用的错误信息一样, 一个 API 应当以一种已知的可使用的格式来提供有 用的错误信息。 错误的表示形式应当和其它任何资源没有区别,只是有一套自己的字段。API 应当总是返回有意义的 HTTP 状态代码。API 错误通常被分成两种类型: 代表客户端问题的 400 系列状态码和 代表服务器问题的 500 系列状态码。最简情况下,API 应当把便于使用的 JSON 格式作为 400 系列错误的标准化表 示。如果可能(意思是,如果负载均衡和反向代理能创建自定义的错误实体), 这也适用于 500 系列错误代码。一个 JSON 格式的错误信息体应当为开发者提供几样东西 - 一个有用的错误信息,一个唯一的错误代码 (能够用来 在文档中查询详细的错误信息) 和可能的详细描述。这样一个 JSON 格式的输出可能会像下面这样: 1{ 2 &code& : 1234, &message& : &Something bad 3 happened :(&, &description& : &More details about the error 4 here& 5}对 PUT, PATCH 和 POST 请求进行错误验证将需要一个字段分解。下面可能是最好的模式:使用一个固定的顶层 错误代码来验证错误,并在额外的字段中提供详细错误信息,就像这样:0 { 1 0 &code& :2 1024, 0 &message& : &Validation3 Failed&, 0 4 [ 0 5 { 0 &code& : &errors& :6
&, &field& : &first_name 0&message& : &First name cannot have fancy8 characters& 0 9 , 1 0 { 1 &code& : }1
&, 1 &message& : &Password cannot be &field& : &password3 blank& 1 4 } 1 ] 5 1 6}HTTP 状态代码 HTTP 定义了一套可以从 API 返回的有意义的状态代码。这些代码能够用来帮助 API 使用者对不同的响应做出相应 处理。我已经把你必然会用到的那些列成了一个简短的清单:?200 OK (成功) - 对一次成功的 GET, PUT, PATCH 或 DELETE 的响应。也能够用于一次未产生创建活动 的 POST?201 Created (已创建) - 对一次导致创建活动的 POST 的响应。 同时结合使用一个位置头信息指向新资源 的 位 置 - Response to a POST that results in a creation. Should be combined with a Location header pointing to the location of the new resource? ? ? ?204 No Content (没有内容) - 对一次没有返回主体信息(像一次 DELETE 请求)的请求的响应 304 Not Modified (未修改) - 当使用 HTTP 缓存头信息时使用 304 400 Bad Request (错误的请求) - 请求是畸形的, 比如无法解析请求体 401 Unauthorized (未授权) - 当没有提供或提供了无效认证细节时。如果从浏览器使用 API,也可以用来触 发弹出一次认证请求? ? ? ? ? ? ?403 Forbidden (禁止访问) - 当认证成功但是认证用户无权访问该资源时 404 Not Found (未找到) - 当一个不存在的资源被请求时 405 Method Not Allowed (方法被禁止) - 当一个对认证用户禁止的 HTTP 方法被请求时 410 Gone (已删除) - 表示资源在终端不再可用。当访问老版本 API 时,作为一个通用响应很有用 415 Unsupported Media Type (不支持的媒体类型) - 如果请求中包含了不正确的内容类型 422 Unprocessable Entity (无法处理的实体) - 出现验证错误时使用 429 Too Many Requests (请求过多) - 当请求由于访问速率限制而被拒绝时总结一个 API 是一个给开发者使用的用户接口。要努力确保它不仅功能上可用,更要用起来愉快。}

我要回帖

更多关于 php接口 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信