当前位置:首页 » 硬盘大全 » 缓存api学习
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

缓存api学习

发布时间: 2022-04-30 12:46:25

A. 如何采用api方式进行全局缓存部署

使用gacutil.exe工具安装:gacutil -i "要注册的dll文件全路径"。

"gacutil.exe”工具为.NET自带工具 (C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin)

在开始运行中输入"cmd”进入命令窗口,通过CD选择到"gacutil.exe”文件所在的目录,

或者 使用Visual Studio 命令提示符

如在命令行输入: gacutil -i D:/Microsoft.SharePoint.dll

可以输入‘gacutil -?’查看帮助

B. API是什么意思API文档又是什么意思

API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

API文档是一个技术内容交付文件,包含如何有效地使用和集成api的说明。它是一个简明的参考手册,包含了使用API所需的所有信息,详细介绍了函数、类、返回类型、参数等,并有教程是示例支撑。

API文档传统上是使用常规内容创建和维护工具和文本编辑器完成的。API描述格式如OpenAPI /Swagger规范具有自动文档编制流程,它使得团队更容易生成和维护API文档。

(2)缓存api学习扩展阅读:

Windows API

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)来实现的。

C. API有什么作用,他的工作原理是什么

这个我本来不想说的,不过也许你知道其它人不知道,这里为了照顾一下新手,不得不说些废话,请大家谅解。
Win32 API即为Microsoft 32位平台的应用程序编程接口(ApplicationProgramming Interface)。所有在Win32平台上运行的应用程序都可以调用这些函数。
使用Win32 API,应用程序可以充分挖掘Windows的32位操作系统的潜力。Mircrosoft的所有32位平台都支持统一的API,包括函数、结构、消息、宏及接口。使用 Win32 API不但可以开发出在各种平台上都能成功运行的应用程序,而且也可以充分利用每个平台特有的功能和属性。
以上为API的相关介绍,不过有些新手看了以后可能还是不怎么明白API到底有什么用?这里请不要着急,如果你有足够耐心的话,请慢慢往下看。

二、如何使用API?
估计这才是大家真正关心的,那么如何使用API呢?在了解API之前,先打开你的VB书,翻到过程函数这章来,在搞清楚API之前应该先搞懂过程函数是怎么一回事!如果你还不知道过程的工作方式,那么请先不要急着往下看,那样容易走很多弯路。

好了,当你理解了过程函数时,也就是你可以使用API的时候了,别把API看得太难,你就像使用过程函数一样使用API就可以了。首先,让我们看看一个简单的API,以下:

Private Declare Sub Sleep Lib "kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)

以上这个API的呢是起一个延时作用。你如果是刚接触API的话可能会感到API的书写及其复杂,而且会感到很不适应。其实这没什么的,慢慢习惯就好了。至于API这些复杂的书写你就不用操心了,在你安装VB的时候微软已经帮我们带上了API浏览器,这些全部都可以利用API浏览器帮我们自动生成。API浏览器的位置位于[开始菜单-程序-Microsoft Visual Basic 6.0 中文版-Microsoft Visual Basic 6.0 中文版工具-API 文本浏览器]。打开API浏览器,在最上面的一个文本框中输入Sleep,这时下面列表框中就会自动显示相应的API函数,然后点右边添加按钮即可,接着点击复制按钮,这时你就可以用Ctrl+V把声明的API添加到VB代码窗口中了。

这里我要说一下,有些新手可能还弄不明白。API的声明范围一般有两种模式,一种是Private(私有的),一种是Public(公用的)。一般Private是声明在类模块或窗体类中,Public声明在模块中。你在添加API的时候,添加按钮下面就有API的声明范围,可以根据自己的需要进行添加。这里我们一般选择私有的(Private)就可以了。

经过上面,我们知道如何添加API,接着我们分析一下API声明,这是你了解API必备的。首先看第一个单词Private,很显然,我上面刚刚讲过,这是申明一个私有的API变量。再看第二个Declare,这个单词帮我们告诉VB是在申明API函数,一般申明外在的API函数时都必须带上这个单词。第三个Sub,别告诉我你不知道什么意思?这就是我叫你先学习VB中过程函数的意思,这个说白了就是没有反回值,一般如果不是Sub而是Function都带有反回值的。第四个Lib,这个是告诉VB我们要声明哪一个DLL中的API函数,也就是告诉VB我们要申明第五个单词kernel32.dLL中的API,一般写DLL名称时都要用双引号括起来,如"user32"、"shell32.dll"等,至于后面的.dll这个可以带可不带。再来看第六个Alias,这个也是需要同后面一个一起用的,我们应该把第六个和第七个连起来一起看Alias "Sleep",这个意思表示将被调用的过程在DLL中还有另外的名称,这个是可选的。最后括号里面的,也就是和过程函数一样,你传入相应的值就可以了。

上面我们分析完API函数声明以后,接着我们就要自己动手写代码了。先把这个API复制到Form1代码窗口中,然后写如下代码:

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Sub Form_Load()
Sleep 2000
End Sub

解释一下,也就是在窗体启动时使用Sleep API进行延时2秒,后面的参数dwMilliseconds是表示你要延时的秒数,基本上和设置Timer中的秒数一样。你再看一下Sleep2000的使用方式,是不是和使用VB过程函数一样呢?好了,我们的第一个VB API程序写完了,可以看到使用API并不是一件很难的事。

三、如何才能提升你对API的学习兴趣?

API,我常把它看做成过程函数,不过每人都有每人的见解和理解方式,自己的理解方式只要可以帮助自己更好的学习和掌握API,也没必要一定要学习他人的。

1,自己做MsgBox

了解API参数的使用方法是很重要的,这里我们不用VB的MsgBox,直接使用API弹出MsgBox消息框。首先,打开API浏览器,选择MessageBox,大家可以用这个API和VB内置的MsgBox比较一下,其实MsgBox也就是MessageBox的缩写,只不过一个是API,一个是VB内置的,但两者都是通过API进行工作的。好了,选择私有声明方式,粘贴到VB代码编辑窗口中,然后新建一个CommandButton,写入以下代码:

Private Declare Function MessageBox Lib "user32" Alias "MessageBoxA"
(ByVal hwnd As Long, ByVal lpText As String, ByVal lpCaption As String,
ByVal wType As Long) As Long
Private Sub Command1_Click()
MessageBox Me.hwnd, "这里是内容", "标题", 0
End Sub

先让我们来分析一下,首先看第一个参数Byval hWnd As Long,很显然这是一个长整形变量,所以我们这里需要传递的是数字,你可能会发现我们传递的并不是数字啊,而是 Me.hwnd??很奇怪是吗?如果你真的有此疑问说明你是真心想要学习好API的,现在就让我们来看看Me.hwnd到底是什么东西?以下摘自VB帮助文档:
hWnd 属性:返回窗体或控件的句柄。
句 柄:是由操作环境定义的一个唯一的整数值,它被程序用来标识或者切换到对象,如窗体或控件等。

现在估计你差不多就已经明白了,我们调用的hwnd其实是一个句柄整数值,你可以用 Msgbox Me.hwnd看一下就知道了。至于Me这是一个关键字,代表当前Form窗体对象。如:Me.Caption="标题"、Me.BackColor=vbRed等。

接上面的,首先我们传入了Me.hwnd,表示是当前窗口调用MessageBox,这里告诉大家一个技巧,也就是以后凡是看到Byval hwnd As Long,一般都是需要传入句柄的,至于传入哪个对象句柄,那就要看你是怎么实现的了。
ByVal lpText As String,这个是字符串变量,标识着叫我们需要传入字符串进去,可以看里面的变量字符lpText,属于文本的意思,也就是说是用来显示MsgBox中的消息文本的。
ByVal lpCaption As String,也是字符串变量,还是传入字符串进去。在看里面的变量字符lpCaption,其实就是显示MsgBox标题的。
ByVal wType As Long,这是一个整形变量,需要传递整形数字,还是看里面的变量字符wType,标识着显示MsgBox类型,这里可以像VB的MsgBox一样使用,如这里可以传入:vbYesNo,vbOkCancel等,如果忽略那就传入0即可。

好了,按F5启动程序,点击Command1,接着就会弹出一个消息框,这里我们制作以及分析MsgBox已经完成了。希望你能在这段学习到一些知识。

2,来点实用的吧

就拿隐藏Windows任务管理器来说吧,这里只能隐藏任务管理器中的窗口,不能隐藏进程。(问:有没有隐藏进程的?答:你想干什么?),当程序运行后你无法从任务管理器的窗口中关闭程序,只能从进程中进行终止。好了,还是老规矩,打开API浏览器,输入GetWindow和ShowWindow两个API,声明范围还是私有的,复制粘贴到Form代码窗口中,嗯,好了?别急,还是API浏览器,选择Combox中的常数,输入GW_OWNER和SW_HIDE这两个API常数,然后粘贴到代码窗口中,问我这两个是干什么的?那就接着往下看吧。写入以下代码:

Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long,
ByVal wCmd As Long) As Long
Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long,
ByVal nCmdShow As Long) As Long
Private Const GW_OWNER = 4
Private Const SW_HIDE = 0
Private Sub Form_Load()
Dim lphWnd As Long
lphWnd = GetWindow(Me.hwnd, GW_OWNER)
ShowWindow lphWnd, SW_HIDE
End Sub

又到了分析的时候了,这对刚入门的新手可谓是最激动的时候了。好了,还是老子,看看两个API的表面意思和传递值变量。

先看GetWindow,表面意思:获取窗口。传递值变量:hWnd整形句柄,wCmd整形命令值。
再看ShowWindow,表面意思:显示窗口。传递值变量:hWnd整形句柄,nCmdShow整形命令值。

然后是使用代码,先看lphWnd = GetWindow(Me.hwnd, GW_OWNER)这句,这句意思是获取当前窗口的所有者窗口句柄,可以看到GetWindow是Function过程函数,执行以后会返回相应的窗口句柄值,这个值为Long整形(同句柄)。接着调用ShowWindow lphWnd, SW_HIDE,这句意思是显示lphwnd这个句柄的窗口,关键一句是最后的SW_HIDE,这是API函数的常量。通过设置常量能让系统知道API到底应该怎么执行显示窗口,是显示?还是隐藏?Hide当然是隐藏的意思。好了,编译成Exe,运行后打开任务管理器,查看程序窗口,还有吗?

我又要说一下了,有些人可能不懂为什么要用GW_OWNER这些常量,这些到底有什么用?还有就是我怎么知道哪些API对应哪些的常量?其实这些常量你只要稍微注意一下就知道它们是怎么回事了,如在GetWindow中我使用GW_OWNER,在ShowWindow中我使用SW_HIDE这些常量都有一个共同的特点,就是他们都是以API的单词第一个字母为标准。如GetWindow相对应的常量就是Get(G)Window(W)=GW,ShowWindow相对应的常就是Show(S)Window(W)=SW,这些常量可以自己在VB的API浏览器中找找看。

3,我还想写下去,不过我不知道写得怎么样,先发出来看看大家的反应再说。大家如果发现有什么不对的地方尽请指出,我接受大家的批评。。。。

D. 请教iOS app REST api 缓存方案

1. 自己手写保存、读取core data;
2. 使用restKit(https://github.com/RestKit/RestKit);
3. AFIncrementalStore;
4. NSURLCache。

E. API入门的书籍~

如果你有SDK编程经验,你就查找MSDN吧。这是最好的API资料
API不用什么入门的,引用一篇文章你看看,AOGO汇编站的:
虽然是针对MASM32写的,但API在所有的windows编程语言中都一样,相对来说,c++和ASM32调用API简单一些,VB调用就麻烦的多————————

使用MASM写Windows程序,其实就是和Windows API打交道,而一个人是不可能记住所有的API用法的,所以API参考手册是必不可少的,API的参考手册中函数原型是按匈牙利表示法表示的,下面这个表就是API原型中那些前缀的详细解释,希望对初学者有帮助。

资料来源:MicroSoft MSDN Platform SDK 参考
a Array 数组
b BOOL (int) 布尔(整数)
by Unsigned Char (Byte) 无符号字符(字节)
c Char 字符(字节)
cb Count of bytes 字节数
cr Color reference value 颜色(参考)值
cx Count of x (Short) x的集合(短整数)
dw DWORD (unsigned long) 双字(无符号长整数)
f Flags (usually multiple bit values) 标志(一般是有多位的数值)
fn Function 函数
g_ global 全局的
h Handle 句柄
i Integer 整数
l Long 长整数
lp Long pointer 长指针
m_ Data member of a class 一个类的数据成员
n Short int 短整数
p Pointer 指针
s String 字符串
sz Zero terminated String 以0结尾的字符串
tm Text metric 文本规则
u Unsigned int 无符号整数
ul Unsigned long (ULONG) 无符号长整数
w WORD (unsigned short) 无符号短整数
x,y x, y coordinates (short) 坐标值/短整数
v void 空

比如说API函数CreateWindowsEx,API原型如下:
HWND CreateWindowEx(
DWORD dwExStyle, // extended window style
LPCTSTR lpClassName, // pointer to registered class name
LPCTSTR lpWindowName, // pointer to window name
DWORD dwStyle, // window style
int x, // horizontal position of window
int y, // vertical position of window
int nWidth, // window width
int nHeight, // window height
HWND hWndParent, // handle to parent or owner window
HMENU hMenu, // handle to menu, or child-window identifier
HINSTANCE hInstance, // handle to application instance
LPVOID lpParam // pointer to window-creation data
);
那么根据上述前缀表可以得出,dwExStyle需要一个双字值,lpClassName与lpWindowName需要一个指向字符串的长指针(在MASM中则是偏移地址),x、y表示需传递整数值,nWidth与nHeight表示传递短整数,hWndParent表示需要一个窗口句柄,hMenu表示传递一个菜单句柄,hInstance表示传递的是程序实例句柄,lpParam表示可以传递长指针(地址)。
注意看前缀时请不要看前面的类型说明符,而是要看词的前缀,如DWORD dwExStyle,只需要看dwExStyle就知道传递的是双字数。
另外还有其它的组合,只要稍注意就能行,比如说lpfn表示指向函数的长指针,在MASM中则是一个函数的地址,,还有像lpSecurityAttributes之类的,则是指向SECURITY_ATTRIBUTES结构的长指针(地址),lpvBuffer表示传递一个缓存(Buffer)长指针(lp)或者为空(void),还有一些没有前缀的则是这个词已经足够说明它的意思了。等等,熟悉这些前缀的含义可以让你在学习API的时候进行快速的掌握。并能排除一些错误。

F. 如何 服务全局缓存jsapi

我的工程里每2个小时自动启动job获取jsapi_ticket,accessToken等有时限的数据,获取后缓存在memcached里,然后也更新在数据库里,但每次读取的时候都是从memcached里取,数据库只是备查用的

G. 如何设计好的RESTful API

安全是恒久的话题,对于基于WSDL和SOAP的Web Service,我们有WS-Security这样的安全规范来指导实现认证、授权、身份管理等安全需求。那么,RESTful API有无成熟可用规范或实现框架呢?如何保证RESTful API的安全性呢?
如何对RESTful API进行版本控制,请分享您认为实用的做法?
HTTP1.1规范中给出的动词对于设计RESTful API够用吗?您在实际项目中会扩展自己的动词吗?在什么情况下需要扩展?
今年5月份发布的JAX-RS 2.0规范对于RSTfulAPI的设计最有价值的特性是哪个(些)? 它(们)用于解决什么问题?
能否为InfoQ的读者们推荐一款实用的RESTful API开发框架,并说明您的推介理由。
HTTP2.0规范正在制定当中,您对它的期待是什么?
InfoQ:什么是好的RESTful API?相信每个人都有自己的评判标准。那么,您认为一个好的RESTful API应该具有哪些特征呢?

李锟:一个好的RESTful API,应该具备以下特征:
这个API应该是对浏览器友好的,能够很好地融入Web,而不是与Web格格不入。
浏览器是最常见和最通用的REST客户端。好的RESTful API应该能够使用浏览器+HTML完成所有的测试(不需要使用编程语言)。这样的API还可以很方便地使用各种自动化的Web功能测试、性能测试工具来做测试。Web前端应用(基于浏览器的RIA应用、移动App等等)也可以很方便地将多个RESTful API的功能组合起来,建造Mashup类的应用。
这个API中所包含的资源和对于资源的操作,应该是直观和容易理解的,并且符合HTTP协议的要求。
REST开发又被称作“面向资源的开发”,这说明对于资源的抽象,是设计RESTful API的核心内容。RESTful API建模的过程与面向对象建模类似,是以名词为核心的。这些名词就是资源,任何可命名的抽象概念都可以定义为一个资源。而HTTP协议并不是一种传输协议,它实际提供了一个操作资源的统一接口。对于资源的任何操作,都应该映射到HTTP的几个有限的方法(常用的有GET/POST/PUT/DELETE四个方法,还有不常用的PATCH/HEAD/OPTIONS方法)上面。所以RESTful API建模的过程,可以看作是具有统一接口约束的面向对象建模过程。
按照HTTP协议的规定,GET方法是安全且幂等的,POST方法是既不安全也不幂等的(可以用来作为所有写操作的通配方法),PUT、DELETE方法都是不安全但幂等的。将对资源的操作合理映射到这四个方法上面,既不过度使用某个方法(例如过度使用GET方法或POST方法),也不添加过多的操作以至于HTTP的四个方法不够用。
如果发现资源上的操作过多,以至于HTTP的方法不够用,应该考虑设计出更多的资源。设计出更多资源(以及相应的URI)对于RESTful API来说并没有什么害处。
这个API应该是松耦合的。
RESTful API的设计包括了三个循序渐进、由低到高的层次:资源抽象、统一接口、超文本驱动。正是这三个层次确保了RESTful API的松耦合性。
当设计面向互联网的API时,松耦合变成了一种“必须有”的强需求。紧耦合的API非常脆弱,一旦公布出去,服务器端和客户端都无法持续进化。尤其是服务器端,公布出去的接口根本不敢改,改了之后,几乎所有客户端应用立即无法正常工作。REST这种架构风格就是紧耦合API的解毒剂,这个话题可以谈的很深,这里就不展开了。感兴趣的读者可以参考《REST实战》。
这个API中所使用的表述格式应该是常见的通用格式
在RESTful API中,对于资源的操作,是通过在服务器端-客户端之间传递资源的表述来间接完成的。资源的表述可以有很多种格式,并且在响应和请求中的资源表述格式也会有所不同。GET/POST响应中的资源表述格式,常见的有HTML、XML、JSON;POST/PUT请求中的资源表述格式,常见的有标准的HTML表单参数、XML、JSON。
这些常见表述格式,处理起来非常容易,有大量的框架和库提供支持。所以除非有很合理的要求,通常不需要使用自定义的私有格式。
使用HTTP响应状态代码来表达各种出错情况
HTTP响应状态代码,是HTTP协议这个统一接口中用来表达出错情况的标准机制。响应状态代码分成两部分:status code和reason phase。两部分都是可定制的,也可以使用标准的status code,只定制reason phase。
如果一个所谓的“RESTful API”对于任何请求都返回200 OK响应,在响应的消息体中返回出错情况信息,这种做法显然不符合“确保操作语义的可见性”这个REST架构风格的基本要求。
这个API应该对于HTTP缓存是友好的
充分利用好HTTP缓存是RESTful API可伸缩性的根本。HTTP协议是一个分层的架构,从两端的user agent到origin server之间,可以插入很多中间组件。而在整个HTTP通信链条的很多位置,都可以设置缓存。HTTP协议内建有很好的缓存机制,可以分成过期模型和验证模型两套缓存机制。如果API设计者完全没有考虑过如何利用HTTP缓存,那么这个API的可伸缩性会有很多问题。
李建业:首先说明一下,对REST这个概念,我一般把它理解为REST风格的架构,但是现在实践中最为广泛认知的是HTTP,而它是REST的一个实现,所以RESTful API也可以不太严格的指基于HTTP的API——当然,即使是不严格的时候,API本身也应该力求遵循REST架构风格。
我认为,一个RESTful API最重要的一点应该是——“尽可能少的先验信息”,这一条也同时是我判断一个好的RESTful API的标准。
比如HTTP动词,在实践中,大家可能会常常纠结于有效利用 HTTP 动词,但这却并不是特别重要的事情——除非你理解这么做的价值。HTTP 动词最重要的地方在于它是标准阐明了的行为,也就是说,如果我们的“客户端”遵循约定,那么就不必要发明新的动词,也就不必增加“先验信息”;但是,所谓“先验信息”,针对的是客户端——对API来说就是调用者,对于一些企业内部系统,或者一些传统系统,由于“资源”很稳定,对资源的操作也很稳定,这些系统的“调用客户端”不是浏览器而是另一个系统,此时如果强制对应到HTTP动词,反而会变成额外的“先验信息”,这时我就不会太拘泥HTTP动词,自己制定一套动词放在参数中也可以接受——只要动词不变化,这个系统依然是REST风格的。
再比如Response里面的Content-Type,这个有时会被新手忽略,但这其实很重要,因为一般涉及到系统间协同的API,往往不会使用普通的文本,比较常见的是使用json表达复杂结构,而这与通常的缺省理解不同(缺省一般会认为是text/plain和text/html),所以如果在API中忘记用Content-Type进行区分的话,后续对多种类型的客户端接入的支持就会变成陷阱(我们多次遇到过这个问题)。而如果一开始就检查是否增加先验知识(缺省Content-Type为plain或者允许指定Content-Type),那这一困难就可以避免了。
丁雪丰:首先,应该正确地使用HTTP的统一接口,比如HTTP的动词,如果不分青红皂白清一色POST那显然还有改进的余地;
其次,资源有合适的粒度,可以从三个方面来评判资源的粒度是否合理——网络的效率、表述的大小以及客户端使用时的易用程度;
最后,是表述的设计,除了表述的正文内容,还有其中的URI和链接,这些都是评判一个RESTful API好坏的标准。
马钧:在我看来,一个好的API标准,就是能尽量利用到HTTP协议的特性,将HTTP当成一种转移协议,而不是传输协议。包括但不限于:利用HTTP的各种动词来明确操作;包含有内容协商,可以根据请求头提供的参数选择一个资源最合适的媒体类型、语言、字符集和编码的表现;使用不同的返回代码来描述各种状态。但实际上见到过的很多声称RESTful API,包括国内的和国外的,能符合这些条件的并不多。parse.com提供的API是我见到过的较为不错的RESTful API,可以作为范例参考。
InfoQ:安全是恒久的话题,对于基于WSDL和SOAP的Web Service,我们有WS-Security这样的安全规范来指导实现认证、授权、身份管理等安全需求。那么,RESTful API有无成熟可用规范或实现框架呢?如何保证RESTful API的安全性呢?
李锟:保证RESTful API的安全性,主要包括三大方面:
a) 对客户端做身份认证
b) 对敏感的数据做加密,并且防止篡改
c) 身份认证之后的授权
对客户端做身份认证,有几种常见的做法:
在请求中加签名参数
为每个接入方分配一个密钥,并且规定一种签名的计算方法。要求接入方的请求中必须加上签名参数。这个做法是最简单的,但是需要确保接入方密钥的安全保存,另外还要注意防范replay攻击。其优点是容易理解与实现,缺点是需要承担安全保存密钥和定期更新密钥的负担,而且不够灵活,更新密钥和升级签名算法很困难。
使用标准的HTTP身份认证机制
HTTP Basic身份认证安全性较低,必须与HTTPS配合使用。HTTP Digest身份认证可以单独使用,具备中等程度的安全性。
HTTP Digest身份认证机制还支持插入用户自定义的加密算法,这样可以进一步提高API的安全性。不过插入自定义加密算法在面向互联网的API中用的不是很多。
这个做法需要确保接入方“安全域-用户名-密码”三元组信息的安全保存,另外还要注意防范replay攻击。
优点:基于标准,得到了广泛的支持(大量HTTP服务器端、客户端库)。在服务器端做HTTP身份认证的职责可以由Web Server(例如Nginx)、App Server(例如Tomcat)、安全框架(例如Spring Security)来承担,对应用开发者来说是透明的。HTTP身份认证机制(RFC 2617)非常好地体现了“分离关注点”的设计原则,而且保持了操作语义的可见性。
缺点:这类基于简单用户名+密码机制的安全性不可能高于基于非对称密钥的机制(例如数字证书)。
使用OAuth协议做身份认证
OAuth协议适用于为外部应用授权访问本站资源的情况。其中的加密机制与HTTP Digest身份认证相比,安全性更高。需要注意,OAuth身份认证与HTTP Digest身份认证之间并不是相互取代的关系,它们的适用场景是不同的。OAuth协议更适合于为面向最终用户维度的API提供授权,例如获取隶属于用户的微博信息等等。如果API并不是面向最终用户维度的,例如像七牛云存储这样的存储服务,这并非是OAuth协议的典型适用场景。
对敏感的数据做加密,并且防止篡改,常见的做法有:
部署SSL基础设施(即HTTPS),敏感数据的传输全部基于SSL。
仅对部分敏感数据做加密(例如预付费卡的卡号+密码),并加入某种随机数作为加密盐,以防范数据被篡改。
身份认证之后的授权,主要是由应用来控制。通常应该实现某种基于角色+用户组的授权机制,这方面的框架有不少(例如Spring Security),不过大多数开发团队还是喜欢自己来实现相关功能。
李建业:我不认为安全是RESTful API需要考虑的问题,事实上我觉得这是两个正交的问题。当然,如果使用RESTful API来提供认证、授权和身份管理,那也算是双方有关系,但是这和其它风格的API设计所要考虑的问题似乎没什么区别,不值得特别注意。
但是在具体设计层面,这两者的“正交点”上似乎确实有些问题,因为REST是一个推崇状态无关原则的架构风格,而认证和授权通常基于第三方解决方案,所以往往会出现违背有状态约束的问题,这个地方我也没有特别的想法,当然这个困难和原问题关系不大。
至于WS-族的协议,我不太了解,不太能参与讨论。
丁雪丰:对于RESTful API,常见的安全措施都是可以继续使用的。例如,为了防篡改,可以对全部参数进行签名;为了防范重放攻击可以在请求中增加一次性的Token,或者短时间内有效的Token;对内容加密可以实现数据防泄露……;对于DDoS攻击,各种HTTP流量清洗策略,都可以继续发挥作用,因为这就是基本的HTTP请求。
在授权和认证方面,OAuth 2.0已经基本成熟了,并且得到了广泛地应用。如果可以,接入第三方账户体系是个不错的选择,比如Google和Facebook的,国内的当然也有几个候选。
马钧:个人认为RESTful的安全性分为几个层次,在安全要求较高的场合,可以通过HTTPs这样的加密协议来保证网络层的安全,应用层的安全可以通过OAuth实现认证,而对于资源的访问授权,则只能依靠应用程序来实现了。
InfoQ:如何对RESTful API进行版本控制,请分享您认为实用的做法?
李锟:一个比较简单实用的做法是直接在URI中插入版本号,这样做允许多个版本的API并行运行。
另一个做法是在HTTP请求中加入自定义头信息,标明使用的版本号。不过这个做法其实对浏览器不够友好,简单地使用浏览器+HTML无法测试。
李建业:目前比较好的方式还是在uri设计中添加版本信息,其它方法都不如这个实用。
丁雪丰:个人认为最好的版本化,就是没有明显的版本。在对已发布的服务进行变更时,要尽量做到兼容,其中包括URI、链接和各种不同的表述的兼容,最关键的就是在扩展时不能破坏现有的客户端。例如,要变更一个参数,可以选择同时兼容新旧两种输入,或者保持老参数不动,提供一个新的参数,在文档中必须做出说明,不推荐新用户再继续使用之前的参数。
如果必须要进行不兼容的变更,那么可以选择标记不同的版本号,这时可以选择在路径或参数中增加版本信息。也有做法是增加HTTP标头,只是在调用时会稍有不便,推荐前两种方法。
马钧:RESTfulAPI的版本升级,尽量兼容之前的版本,保证原有的API都能正常工作,可以通过HTTP 301转跳到新的资源。另外一种实用的做法就是在url中保留版本号,同时提供多个版本供客户端使用,如 v1.rest.com 或者 rest.com/v1/ 这样。
InfoQ:HTTP1.1规范中给出的动词对于设计RESTful API够用吗?您在实际项目中会扩展自己的动词吗?在什么情况下需要扩展?
李锟:这个问题取决于设计者如何看待和设计资源。如果资源抽象做的很好,对于某个资源的任何操作,通常都能够映射到CRUD四个类别中。CRUD四个类别对于操作资源来说,绝大多数情况下是完备的。HTTP的GET/POST/PUT/DELETE四个方法,对于CRUD四个类别的操作来说是足够的,映射关系是Create-POST/Retrieve-GET/Update-PUT/Delete-DELETE。
我们通常不会选择创建自己的动词,这样做对于客户端开发者来说,需要更多的学习成本。如果在资源上定义的操作过多,我们会选择拆分出更多的资源。
李建业:一般是够用的,有时一些“不够用”的场景是由于我们没有设计出合理的资源,比如批量操作。但是,正如之前所说的那样,对于某些内部的、传统的(因此模型稳定且已知)系统,API提供者和调用者会有自已的固定动词表,此时没必要拘泥。另外,我不建议扩展动词,一旦扩展了动词,其实已经破坏了我之前说的*“尽可能少的先验信息”*,那么,扩展动词和重新设计动词的成本差别不大。基于这个考虑,我建议尽可能保持动词不变,除非你想重新设计动词表。
丁雪丰:一般情况下,常用的HTTP动词是够用的,并没有出现一定要自己扩展动词的情况。其实,最常用的也就是GET、POST、DELETE和PUT,而HEAD、OPTIONS、TRACE则基本用不太到。如果出现一时找不到合适的动词,安全幂等的操作用GET,其他都可以用POST,在设计资源时稍加考虑即可。
马钧:在我的实际项目中,只用到了POST,PUT,DELETE,GET这四个动词。
InfoQ:今年5月份发布的JAX-RS 2.0规范对于RSTfulAPI的设计最有价值的特性是哪个(些)? 它(们)用于解决什么问题?
李锟:REST开发框架RESTEasy项目负责人Bill Burke,去年写了一篇文章介绍JAX-RS 2.0。
我同意Bill在文章中的观点,在JAX-RS 2.0增加的内容中,最重要的三部分为:
a) Client API——用来规范化JAX-RS客户端的开发方式。
b) Server-side Asynchronous HTTP——用来实现服务器端推送功能,而不需要依靠低效的轮询方式。
c) Filters and Interceptors——用来分离关注点,将鉴权、日志等逻辑与业务逻辑分离开,更好地实现代码重用。
这三部分的内容对于开发者来说都很有用。遵循JAX-RS规范做开发,可以确保服务器端以及客户端代码的可移植性。
李建业:我个人关注异步API这部分,主要是因为流式服务将会越来越多,那将大量需要这类支持。
InfoQ:能否为InfoQ的读者推荐一款实用的RESTful API开发框架,并说明您的推介理由。
李锟:这个问题我就不详细回答了。不同的编程语言有不同的REST开发框架,对于REST的支持程度也不同。开发RESTful API的需求范围很广,可选择的开发框架的范围也很广。保持多样性是繁荣生态环境的基础。像Java就有支持JAX-RS规范的Jersey、RESTEasy、Restlet、Apache CXF,和不支持JAX-RS规范的Spring MVC等等很多框架。这些框架目前都做的不错。我对框架的选择没有倾向性。RESTful API设计的最佳实践应该是通用的,而不是必须依赖某种特定的开发框架。
李建业:不好意思,这个我不太重视,没法推荐,不过我可以解释一下为什么对RESTful API框架不感冒的原因。
REST作为一个架构风格,对我们的系统开发有很大影响,但是这些影响一般是针对架构(例如状态无关)或者设计(例如资源识别)上的,所以一旦涉及到具体实现,主要工作就基本结束了,此时开发框架能做的事也就只有简化编程了(相较而言,有的框架还能起到引导设计的作用),而由于RESTful会抽象动词,所以实现层面中和API规范相关的工作本来就不多,那么框架的价值就更小了。
当然,我们也不可能直接基于servlet/rakc/wsgi来开发,不过一般的编程语言都会提供一些简单的url route/match策略,我们使用这些就足够了。另外,有些框架能帮我们生成全部的动词支持,但这也未必是好事,我一般倾向于按需实现——用到了再支持,这就更不需要太关注开发框架对RESTful的支持了。
丁雪丰:由于本人是Spring的拥护者,工作中也一直在使用Spring,所以在选择框架时会更多地倾向Spring MVC(并不是说别的框架不好,这里有些个人主观的成份)。如果一定要选择其他框架,也要选择能够方便与Spring集成的框架。如果在项目中已经使用了Spring,那么没有什么理由不选择Spring MVC,鉴于目前Spring在各种项目中的高出镜率,相信一般情况下都会选择Spring MVC。
REST的成熟度模型中,第三层就是HATEOAS,Spring目前还提供了Spring Hateoas子项目,对链接、资源等方面的支持都做了一定的增强。
马钧:我目前在实际项目中使用的是Spray,这是一个开源的 REST/HTTP 工具包和底层网络 IO 包,基于 Scala 和 Akka 构建。轻量级、异步、非堵塞、基于 actor 模式、模块化和可测试是Spray的特点。
InfoQ:HTTP2.0规范正在制定当中,您对它的期待是什么?
李锟:我的期待包括两个方面:应该做的和不应该做的。
HTTP/2.0规范应该做的:
与HTTP/1.1协议保持兼容。兼容的含义是说两者可以并存,客户端应用可以根据服务器端的能力,自由地选择使用HTTP/2.0还是HTTP/1.1,而且选择过程对应用来说是透明的。
改进HTTP协议(作为资源的统一接口)之中操作语义表达方式的语法,提高网络传输效率。
更好地模块化,这样HTTP/2.0协议的实现能够更好地模块化。应用程序可根据需要选择适当的模块,而不是要么全有、要么全无。
废弃掉HTTP/1.1协议中一些很少有人用到的部分,例如采用管道(pipelining)方式发送请求。
增加更多的动词,以适应除CRUD之外的其他场景。
HTTP/2.0规范不应该做的:
HTTP/2.0协议不应该把底层的数据加密机制(即SSL)作为必选项。
HTTP/2.0协议不应该背离REST架构风格的约束,尤其是要确保操作语义对于中间组件的可见性。
在上面这两个方面,Roy Fileidng曾经与SPDY协议设计者Mike Belshe发生过激烈争论,详情请看:Roy Fielding谈Google SPDY协议
李建业:对此规范关注不多,不知道会不会有对于流的支持,目前我所知道的只有chunk方式进行简单的支持,但是真正的流需要区分数据通道和控制通道——哪怕是逻辑上的区分,这样就直接对REST风格产生了很大冲击,考虑到流式服务在未来的发展潜力,我特别期待业界在这方面有所进展。
丁雪丰:HTTP 2.0很大程度上是借鉴了Google的SPDY,就我而言,首先,希望这个规范能做到与HTTP 1.1的兼容,使用者如果只认识1.1,那么2.0能优雅“降级”;其次,希望2.0能带来更好的性能,SPDY在这方面还是有所改进的,希望HTTP 2.0能再接再厉;最后,希望这个规范能在最终定稿时附带一个最佳实践,正确引导人们合理地使用HTTP 2.0。
马钧:没研究过,估计即使出来,1.1还有很长的生命周期,不会很快被取代。