RESTful WebServices 讀書筆記

第一章 Programmable Web及其分類

P36,很多Web服務器都把作用域信息放在URI路徑裏。另一種選擇是把作用域信息放在實體主體裏,SOAP Web服務通常都採用這種方式,SOAP信封裏含一個q標籤(tag),起內容爲字符串“REST”-這就是作用域信息。

採用什麼樣的服務設計,決定了哪些信息屬於方法信息,哪些信息屬於作用域信息。下面兩個URI包含同樣的信息:

http://fickr.com/photos/tags/penguin

http://api.flickr.com/services/rest?method=flickr.photos.search?tags=penguin

在前一個URI裏,方法信息是“獲取(GET”,作用域信息是“具有“‘penguin’標籤的照片”;而在後一個URI裏,方法信息是“搜索照片”,作用域信息是“penguin”.

P37,常見的Web服務架構主要有三種:REST式架構、RPC式架構和REST-RPC混合架構。

REST式、面向資源的架構:REST式架構意味着,方法信息都在http方法裏;面向資源的架構(ROA)意味着,作用域信息都在URI裏-二者結合起來是很強大的。

RPC式架構:RPC式Web服務通常從 客戶端收到一個充滿數據的信封,然後發回一個同樣充滿數據的信封。RPC式架構意味着:方法信息和作用域信息都在信封或報頭裏。HTTP是一種常見的信封格式,另一種常見的信封格式是SOAP(把SOAP信封放在HTTP信封裏,在HTTP上傳送SOAP文檔)。各個RPC式服務採用自己的詞彙,就像計算機程序一樣(你每次寫程序,定義的函數名稱都不相同。)而REST式Web服務則相反,它們公用一套標準詞彙,即HTTP方法。REST式服務裏的每個對象都具有統一的基本接口。XML-RPC是最典型的RPC架構的例子。

P39,REST式服務爲不同的作用域信息暴露不同的URI;而RPC式服務一般爲每個“文檔處理器”暴露一個URI,而且這裏的HTTP信封是空的-它是一個沒有實體主體的HTTP GET請求。

較多采用或只採用HTTP POST的服務,多半是RPC式服務。如果一個REST式服務過多的採用HTTP POST,那麼它就容易演變爲REST-RPC混合架構。

P42,Programmable Web涉及的技術

HTTP:所有的Web服務都用HTTP,只是它們使用的方式有所不同。對於一個REST式Web服務,它會在HTTP方法裏尋找方法信息,在URI裏尋找作用域信息;而RPC式Web服務則往往忽略HTTP方法,在URI、HTTP報頭或實體主體裏尋找方法信息與作用域信息。有些RPC式Web服務把HTTP作爲一種容納文檔的信封,而另一些RPC式Web服務則把HTTP作爲一種容納另一個信封的信封。

URI:所有的Web服務都用URI,只是它們使用的方式有些差別:一個REST式面向資源的服務爲客戶端可能操作的每一則數據暴露一個URI;一個REST-RPC混合服務,爲客戶端可能進行的每一個操作暴露一個URI(比如獲取數據用一個URI,刪除數據用另一個URI);一個RPC式服務,爲每個處理遠程調用的進程暴露一個URI,一般來說這樣的URI只有一個,即服務的“端點(endpoint)”。

XML-RPC

SOAP :基本上,現在每個採用SOAP的Web服務器都屬於RPC式架構。

WS-*:這些標準定義各種特定用途的SOAP報頭。

WSDL:Web Service Description Language,Web 服務描述語言,是一套用於描述SOAP Web服務的XML詞彙。客戶端通過參考WSDL文檔,可以確切地知道它能夠調用哪些RPC式方法、這些方法需要哪些參數,以及返回值是什麼數據類型。幾乎所有現有的基於SOAP的服務都發布有WSDL文檔,因爲假如沒有WSDL文檔作爲參考的話,將很難使用這些服務。

WADL:Web Application Description Language,Web應用描述語言,是一套用於描述REST式Web服務的XML詞彙。跟WSDL一樣,普通客戶端通過參考相應的WADL文檔,可以瞭解如何使用Web服務的全部功能。由於REST式服務的接口比較簡單,所以WADL之於REST式服務的必要性,並不像WSDL之於RPC式SOAP服務那麼大。

SOA:面向服務的架構,Service-Oriented Architecture

第二章 編寫Web服務客戶端

P47,所有Web服務請求都涉及三個步驟:

1.準備好要放入HTTP請求的數據:HTTP方法、URI、HTTP報頭,以及(對於採用PUT或POST方法的請求而言)需要放進請求實體主體裏的文檔。

2.把這些數據格式化爲一個HTTP請求,然後把HTTP請求發給正確的HTTP服務器。

3.把服務器返回的數據(響應代碼、報頭及實體主體)解析爲一個數據結構,供程序使用。

P52,用HTTP庫發送請求。要構建一個完全通用的Web服務客戶端,需要具備以下特徵的HTTP庫:

1.它必須支持HTTPS和SSL證書驗證。Web服務跟網站一樣,與客戶端的加密通信也是通過HTTPS進行的。許多Web服務根本不接受非加密的HTTP請求。許多庫常要依賴某個外部的C語言SSL庫來提供HTTPS支持。

2.它必須支持至少五個主要的HTTP方法:GET、HEAD、POST、PUT和DELETE。

3.它必須允許程序員定製PUT或POST請求的實體主體裏的數據。

4.它必須允許程序員定製請求的HTTP報頭。

5.它必須允許程序員獲取HTTP響應的響應代碼及報頭,而不是僅能獲取HTTP響應的實體主體。

6.它必須支持通過HTTP代理進行HTTP通信。

可選特性:HTTP庫有一些可選特性,它們將令你在爲REST式或混合架構服務編寫客戶端時方便許多。總的來講,這些特性主要是跟HTTP報頭有關的。

1.爲了節省帶寬,HTTP庫應該請求壓縮格式的數據,並在收到數據時自動解壓。相關的HTTP請求報頭是Accept-Encoding,相關的HTTP響應報頭是Encoding。

2.HTTP類應該自動把返回的響應緩存起來。當你再次請求同一URI時,它應該返回緩存中的數據(假如服務器上的內容還沒有變的話)。相關的HTTP請求報頭是ETag和If-Modified-Since,相關的HTTP響應報頭是ETag和Last-Modified.

3.HTTP庫應該透明地支持常見的HTTP認證形式,如:基本認證、摘要認證(Digest)及WSSE認證。如果能夠支持(或有插件支持)特定機構專有的認證方法(比如Amazon的)也是很有用的。相關HTTP請求報頭是Authorization,相關HTTP響應報頭(主張認證的一方)是WWW-Authenticate。

4.HTTP庫應該能夠透明地作HTTP重定向(redirect),同時避免無限重定向和循環重定向。這應該作爲一個用戶可選項,而不是每一次都自動作重定向。一個Web服務器可能發回響應代碼303(“See Other”),而不是讓客戶端現在就重定向到哪個URI。

5.HTTP庫應能夠解析並創建HTTP cookie字符串,而不是隻能由程序員手工設置Cookie報頭。雖然對於REST式服務來說,這一點不是很重要(因爲REST刻意避免cookies),但是假如你要使用human web的話,這一特性很重要。

一個用Java編寫的del.icio.us客戶端:

// DeliciousApp.java
import java.io.*;


import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;


import org.w3c.dom.*;
import org.xml.sax.SAXException;
import javax.xml.parsers.*;
import javax.xml.xpath.*;


/**
 * 一個命令行應用程序。它的功能是:從del.icio.us獲取書籤
 * 並把書籤信息打印到標準輸出。
 */
public class DeliciousApp {
	
	public static void main(String[] args)
	throws HttpException,IOException,ParserConfigurationException,
	SAXException,XPathExpressionException{
		if(args.length != 2){
			System.out.println("Usage:java -classpath [CLASSPATH] "
					+ "DeliciousApp [USERNAME] [PASSWORD]");
			System.out.println("[CLASSPATH] - Must contain commons-codec, "+
					"commons-logging, and commons-httpclient");
			System.out.println("[USERNAME] - Your del.icio.us username");
			System.out.println("[PASSWORD] - Your del.icio.us password");
			System.out.println();
			System.exit(-1);
		}
		
		//設置認證證書
		Credentials creds = new UsernamePasswordCredentials(args[0], args[1]);
		HttpClient client = new HttpClient();
		client.getState().setCredentials(AuthScope.ANY, creds);
		
		//發送HTTPS請求
		String url = "https://api.del.icio.us/v1/posts/recent";
		GetMethod method = new GetMethod(url);
		client.executeMethod(method);
		InputStream responseBody = method.getResponseBodyAsStream();
		
		//把響應實體主體轉換爲一個XML文檔
		DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder =docBuilderFactory.newDocumentBuilder();
		Document doc = docBuilder.parse(responseBody);
		method.releaseConnection();
		
		//用XPath表達式來獲取書籤列表
		XPath xpath = XPathFactory.newInstance().newXPath();
		NodeList bookmarks = (NodeList)xpath.evaluate("/posts/post", doc,XPathConstants.NODESET);
		
		//遍歷各個書籤,並打印出每個書籤的信息
		for(int i = 0;i<bookmarks.getLength();i++){
			NamedNodeMap bookmark = bookmarks.item(i).getAttributes();
			String description = bookmark.getNamedItem("description").getNodeValue();
			String uri = bookmark.getNamedItem("href").getNodeValue();
			System.out.println(description + ": "+uri);
		}
		System.exit(0);
	}
}

P61,用XML解析器處理響應:實體主體通常是HTTP響應裏最重要的部分。就Web服務而言,實體主體通常是一個XML文檔,其中包含客戶端所需要的大部分信息。這些信息,在經過XML解析器(XML parser)解析之後,便可爲客戶端所用。

XML解析器分爲三種,有兩種基本的XML解析策略:基於文檔的策略(如DOM等樹式解析器)和基於事件的策略(如SAX及“拖”是解析器)。每個編程語言都有相應的樹式解析器和SAX解析器;大多數編程語言都有相應的拖式解析器。

基於文檔的樹式策略是三種模型中最簡單的。樹式解析器把XML文檔建模爲一種嵌套的數據結構。這種數據結構一旦生成好,你就可以用XPath查詢、CSS選擇器等來查詢與處理它了。DOM解析器是一種樹式解析器,它實現了一個W3C定義的接口。

樹式策略的優點是易於使用。採用樹式解析器的話,你可以把文檔視爲一個對象。它的最大缺點是:你必須把整個文檔作爲整體來處理。也就是說,你必須在把整個文檔完全轉換爲樹結構以後才能處理它-這需要把整個文檔載入內存,如果遇到大文檔(即使結構比較簡單),這種方式是低效的。要是能“解析一點,處理一點”就好了。

SAX式或拖式解析器把一個XML文檔轉換成一個事件流,而不是數據結構。首標籤、尾標籤、XML註釋及實體聲明等都是事件。

假如幾乎每個事件你都要處理,那拖式解析器是很有用的。拖式解析器允許你一個處理一個事件,即:如果需要,就從事件流裏“拖出”下一個事件。你可以對“拖出”的事件作相應的處理,也可以用它來構建一個數據結構(多半要比樹式解析器構建的數據結構小)供以後使用。你可以在任何時候暫停解析文檔,等需要繼續時,再從事件流裏“拖出”下一個事件。

基於文檔的解析器的優點是,你可以隨機訪問文檔中的內容;而對於基於事件的解析器,事件觸發後,就沒機會再次處理了。如果你想再次觸發它就得重新解析該文檔。而且,假如遇到格式有錯的XML文檔的話,基於事件的解析器要直到處理到出錯的地方纔會報錯和崩潰;因此,假如你不希望回調方法被格式有錯的文檔所觸發,就必須在把XML文檔交給基於事件的解析器處理之前,確保該文檔是良構的。

P67,JSON Parsers:處理序列化數據:雖然大多數Web服務返回的都是XML文檔,不過也逐漸有Web服務返回序列化爲JSON字符串的簡單數據結構(數字、數組、hash等)。JSON通常是供Ajax應用的客戶端部分使用的。其想法是:瀏覽器從JSON數據結構得到JavaScript數據結構,要比從XML文檔得到JavaScript數據結構容易的多。各個Web瀏覽器提供的Javascript版XML解析器接口都略有不同,但JSON串只不過是一個受嚴格約束的Javascript程序,因此它在每個瀏覽器裏的工作方式都一樣。JSON是一種簡單、獨立於語言的“把編程語言數據結構格式化爲字符串”的方式。

總的來說,JSON適用於表達數據結構,而Web提供的主要是文檔-- 一種不規則的、自描述的、相互鏈接的數據結構。XML和HTML專門用於表達文檔。假如用JSON來表示一個網頁,那會很難看,就像用XML來表示數組一樣難看。當你需要描述一個難以適應文檔形式的數據結構時,採用JSON是比較合適的。

P70,WADL簡化客戶端的編寫

對於RPC式Web服務,可以用WSDL(Web Service Description Language,Web服務描述語言)來詳細描述服務,這樣,通用庫就可以根據響應的WSDL文檔來訪問該服務了。

WADL文檔描述了你可以向一個服務發出哪些HTTP請求:你能訪問哪些URI,這些URI期望你發送什麼數據,以及它們能返回什麼呢數據,等等。WADL庫可以解析WADL文檔,並把所有可能的服務請求模擬爲本地語言API。WADL抽象出的是HTTP的細節,而不是背後的REST式接口。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章