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還有很長的生命周期,不會很快被取代。