1乒融、什么是REST格仲?
REST(Representational State Transfer)是Roy Fielding 提出的一個描述互聯(lián)系統(tǒng)架構(gòu)風(fēng)格的名詞二汛。REST定義了一組體系架構(gòu)原則铸董,您可以根據(jù)這些原則設(shè)計以系統(tǒng)資源為中心的Web 服務(wù)灭贷,包括使用不同語言編寫的客戶端如何通過 HTTP處理和傳輸資源狀態(tài)危队。
為什么稱為 REST聪建?Web本質(zhì)上由各種各樣的資源組成,資源由URI 唯一標(biāo)識茫陆。瀏覽器(或者任何其它類似于瀏覽器的應(yīng)用程序)將展示出該資源的一種表現(xiàn)方式金麸,或者一種表現(xiàn)狀態(tài)。如果用戶在該頁面中定向到指向其它資源的鏈接簿盅,則將訪問該資源挥下,并表現(xiàn)出它的狀態(tài)。這意味著客戶端應(yīng)用程序隨著每個資源表現(xiàn)狀態(tài)的不同而發(fā)生狀態(tài)轉(zhuǎn)移桨醋,也即所謂REST棚瘟。
2喜最、REST成熟度的四個層次
第一個層次(Level0)的Web 服務(wù)只是使用 HTTP 作為傳輸方式偎蘸,實(shí)際上只是遠(yuǎn)程方法調(diào)用(RPC)的一種具體形 式。SOAP和 XML-RPC都屬于此類瞬内。
第二個層次(Level1)的Web 服務(wù)引入了資源的概念迷雪。每個資源有對應(yīng)的標(biāo)識符和表達(dá)。
第三個層次(Level2)的Web 服務(wù)使用不同的 HTTP 方法來進(jìn)行不同的操作虫蝶,并且使用HTTP 狀態(tài)碼來表示不同的結(jié)果章咧。如 HTTPGET 方法來獲取資源,HTTPDELETE 方法來刪除資源能真。
第四個層次(Level3)的Web 服務(wù)使用 HATEOAS赁严。在資源的表達(dá)中包含了鏈接信息》垲恚客戶端可以根據(jù)鏈接來發(fā)現(xiàn)可以執(zhí)行的動作疼约。
其中第三個層次建立了創(chuàng)建、讀取秦躯、更新和刪除(create,read, update, and delete忆谓,CRUD)操作與 HTTP方法之間的一對一映射。根據(jù)此映射:
若要在服務(wù)器上創(chuàng)建資源踱承,應(yīng)該使用POST 方法倡缠。
若要檢索某個資源哨免,應(yīng)該使用GET 方法。
若要更改資源狀態(tài)或?qū)ζ溥M(jìn)行更新昙沦,應(yīng)該使用PUT 方法琢唾。
若要刪除某個資源,應(yīng)該使用DELETE 方法盾饮。
3采桃、HTTP請求的方法
- GET:通過請求URI得到資源
- POST:用于添加新的內(nèi)容
- PUT:用于修改某個內(nèi)容,若不存在則添加
- DELETE:刪除某個內(nèi)容
- OPTIONS :詢問可以執(zhí)行哪些方法
- HEAD :類似于GET, 但是不返回body信息丘损,用于檢查對象是否存在普办,以及得到對象的元數(shù)據(jù)
- CONNECT :用于代理進(jìn)行傳輸,如使用SSL
- TRACE:用于遠(yuǎn)程診斷服務(wù)器
4徘钥、HTTP請求的狀態(tài)碼
- 成功Successful 2xx:此類狀態(tài)碼標(biāo)識客戶端的請求被成功接收衔蹲、理解并接受。常見如200(OK)呈础、204(NoContent)舆驶。
- 重定向Redirection 3xx:這個類別的狀態(tài)碼標(biāo)識用戶代理要做出進(jìn)一步的動作來完成請求。常見如301(MovedPermanently)而钞、302(MovedTemprarily)沙廉。
- 客戶端錯誤Client Error 4xx:4xx類別的狀態(tài)碼是當(dāng)客戶端出錯的時候使用的。常見如400(BadRequest)臼节、401(Unauthorized)撬陵、403(Forbidden)、404(NotFound)网缝。
- 服務(wù)器錯誤Server Error 5xx:響應(yīng)狀態(tài)碼以5開頭表示服務(wù)器知道自己出錯或者沒有能力執(zhí)行請求袱结。常見如500(InternalServer Error)、502(BadGateway)途凫、504(GatewayTimeout)。
附HTTP1.1的標(biāo)準(zhǔn)簡介:http://blog.chinaunix.net/uid-9188830-id-2007021.html
5溢吻、RestTemplate
5.1 簡介
Spring's central class for synchronous client-side HTTP access. It simplifies communication with HTTPservers, and enforces RESTful principles. It handles HTTP connections, leaving application code to provide URLs(with possible template variables) and extract results.
簡單說就是:簡化了發(fā)起HTTP請求以及處理響應(yīng)的過程维费,并且支持REST。為什么說簡化了呢促王?
來看兩種實(shí)現(xiàn)方式
(1)使用java.net包下的URLConnection建立連接
String result= "";
BufferedReader in = null;
try {
String urlNameString= url +"?" + param;
URL realUrl= new URL(urlNameString);
// 打開和URL之間的連接
URLConnection connection = realUrl.openConnection();
// 設(shè)置通用的請求屬性
connection.setRequestProperty("accept","*/*");
connection.setRequestProperty("connection","Keep-Alive");
connection.setRequestProperty("user-agent",
"Mozilla/4.0(compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 建立實(shí)際的連接
connection.connect();
// 獲取所有響應(yīng)頭字段
Map<String,List<String>> map = connection.getHeaderFields();
// 遍歷所有的響應(yīng)頭字段
for(String key : map.keySet()) {
System.out.println(key+ "--->" + map.get(key));
}
// 定義 BufferedReader輸入流來讀取URL的響應(yīng)
in =new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String line;
while ((line = in.readLine())!= null) {
result += line;
}
} catch (Exception e) {
…
}
// 使用finally塊來關(guān)閉輸入流
finally{
// 關(guān)閉流
}
(2)使用RestTempalte
ResponseEntity<SsoUrlPrm> result = restTemplate.getForEntity(requestPathUrl,SsoUrlPrm.class);
5.2 對外開放的接口
(1)
DELETE | delete |
GET | getForObject |
getForEntity | |
HEAD | headForHeaders |
OPTIONS | optionsForAllow |
POST | postForLocation |
postForObject | |
PUT | put |
any | exchange |
execute |
(2)每一個小類又分三種方法犀盟,這三種方法有什么區(qū)別?
第一種和第二種的首個參數(shù)都是用String表示一個URI蝇狼。但它們的最后一個參數(shù)分別是Object[]和Map
第三種的首個參數(shù)使用java.net.URI表示一個URI阅畴。且只有兩個參數(shù)。這是因為迅耘,String類型的URI支持占位符贱枣。
比如:restTemplate.getForObject("http://example.com/hotels/{hotel}/bookings/{booking}",String.class,"42", "21");
那么最終訪問的URI為:http://example.com/hotels/42/bookings/21
但是String有一個小缺陷:String形式的URI會被URL編碼兩次(URL encode請自行百度)监署,這就要求服務(wù)器在獲取URI中的參數(shù)時主動進(jìn)行一次解碼,但如果服務(wù)的提供者不這么做呢纽哥?
這時就需要使用不會使用任何編碼的java.net.URI
PS:參數(shù)Class<T> responseType
定義了返回數(shù)據(jù)的類型钠乏。
(3)Exchange
與其它接口的不同:
允許調(diào)用者指定HTTP請求的方法(GET,POST,PUT等)
可以在請求中增加body以及頭信息,其內(nèi)容通過參數(shù)
HttpEntity<?>requestEntity
描述
exchange支持
含參數(shù)的類型
(即泛型類)作為返回類型春塌,該特性通過ParameterizedTypeReference<T>responseType
描述晓避。比如:
List<String> a = new ArrayList<String>();
System.out.println(a.getClass());
System.out.println(a.getClass().getGenericSuperclass());
ParameterizedTypeReference pt = new ParameterizedTypeReference<ArrayList<String>>() {};
System.out.println(pt.getType());
得到的結(jié)果是:
class java.util.ArrayList
java.util.AbstractList<E>
java.util.ArrayList<java.lang.String>
- 這是因為
ParameterizedTypeReference<ArrayList<String>>
并不根據(jù)實(shí)參而是使用getGenericSuperclass()
方法獲取其父類的類型(注意這里的new有花括號,是ParameterizedTypeReference的子類)只壳,父類的類型通過java.lang.reflect.Type描述俏拱,然后通過Type的getActualTypeArguments()獲得了父類的實(shí)參類型,注意得到的Type類吼句,并不是class類锅必。
(4)excute
所有的get、post命辖、delete况毅、put、options尔艇、head尔许、exchange方法最終調(diào)用的都是excute方法。舉個栗子:
@Override
public <T> T getForObject(String url, Class<T> responseType, Object... urlVariables) throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
HttpMessageConverterExtractor<T> responseExtractor = new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, urlVariables);
}
Excute方法只是將String格式的URI轉(zhuǎn)成了java.net.URI终娃,之后調(diào)用了doExecute方法味廊。整個調(diào)用過程
(5)doExcute
5.1 定義
protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback,ResponseExtractor<T> responseExtractor) throws RestClientException {…}
這里需要了解兩個類: RequestCallback &ResponseExtractor
5.2 RequestCallback
Callback interface for code that operates on a ClientHttpRequest. Allows to manipulate the request headers, and write to the request body.
簡單說:用于操作請求頭和body,在請求發(fā)出前執(zhí)行棠耕。
該接口有兩個實(shí)現(xiàn)類:
AcceptHeaderRequestCallback | 只處理請求頭余佛,用于getXXX()方法 |
HttpEntityRequestCallback | 繼承于AcceptHeaderRequestCallback可以處理請求頭和body,用于putXXX()窍荧、postXXX()和exchange()方法辉巡。 |
- DELETE、HEAD蕊退、OPTIONS沒有使用這個接口郊楣。