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式接口。

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