WordPress插件開發(fā)教程手冊 — HTTP API
本教程詳細(xì)介紹了WordPress HTTP API的使用方法,包括GET、POST和HEAD請求的工作原理及實際應(yīng)用。通過示例演示如何與外部API(如Github API)交互,并解析常見的HTTP響應(yīng)碼,幫助開發(fā)者高效開發(fā)WordPress插件。
HTTP 是超文本傳輸協(xié)議,是整個互聯(lián)網(wǎng)的基礎(chǔ),即使這是我們第一次使用 HTTP,我們知道得也可能比認(rèn)為得要多。HTTP 的工作原理如下:
- 你好服務(wù)器 XYZ,請問有文件 abc.html 嗎?
- 你好,朋友,我有這個文件,現(xiàn)在發(fā)給你,接好了。
我們有很多方法可以在 PHP 中發(fā)送 HTTP 請求,WordPress HTTP API 的目的是支持盡可能多的方法,并在各種情況下使用最合適的方法。WordPress HTTP API 也可用于和其他 API(如 Twitter API 或 Google API)進(jìn)行通信和交互。
HTTP 方法
HTTP 有幾種描述特定操作的方法或動詞。WordPress 幫我們預(yù)先建立了三種最常見的功能,每次一個 HTTP 請求時,WordPress 也會傳遞一個方法來幫助服務(wù)器確定客戶端正在請求什么樣的動作。
GET
GET 方法用于從服務(wù)器獲取數(shù)據(jù),這是迄今為止最常用的方法,我們查看網(wǎng)站或者從 API 獲取數(shù)據(jù)的時候,我們都會使用 GET 請求,事實上,我們在閱讀這篇文章的時候,我們使用的瀏覽器就是在幫我們展示從服務(wù)器 GET 到的頁面。
POST
POST 請求用于把數(shù)據(jù)發(fā)送到服務(wù)器,以便服務(wù)器進(jìn)行某種方式的操作,例如,一個聯(lián)系表單。我們把數(shù)據(jù)輸入到這個表單并點擊了提交按鈕,瀏覽器會把我們輸入的數(shù)據(jù)以 POST 的方法發(fā)送給服務(wù)器,服務(wù)器收到數(shù)據(jù)后,會進(jìn)行一些處理。
HEAD
HEAD 請求使用得要比上面兩個少得多,HEAD 與 GET 請求基本相同,是不過 HEAD 請求只獲取關(guān)于數(shù)據(jù)的信息,不獲取數(shù)據(jù)。這些信息描述了數(shù)據(jù)的最后更新時間,客戶端是否應(yīng)該緩存數(shù)據(jù),數(shù)據(jù)的類型等等?,F(xiàn)代瀏覽器通常會向已經(jīng)訪問過的頁面發(fā)送 HEAD 請求,以確定是否需要更新。如果不需要,瀏覽器展示給我們的是緩存在本地的頁面副本,而不用浪費寬帶獲取一個一模一樣的頁面。
所有優(yōu)秀的 API 都應(yīng)該在執(zhí)行 GET 請求之前先使用 HEAD 請求來嘗試節(jié)省帶寬。雖然在有數(shù)據(jù)更新的時候,這種處理方式會發(fā)送兩次 HTTP 請求,但是相對于通過 GET 方法獲取有可能很大的重復(fù)數(shù)據(jù),先使用 GET 請求測試一下還是可以節(jié)省很多帶寬的。只有在 HEAD 請求表示數(shù)據(jù)已被更新或者不應(yīng)該被緩存的情況下直接使用 GET 請求可以節(jié)省一次請求的帶寬和時間。
自定義方法
除了上面介紹的,還有其他 HTTP 方法,比如 PUT,DELETE,TRACE,和 CONNECT,本文不會涉及到這些方法,因為 WorPress 沒有預(yù)先構(gòu)建這些方法,目前為止我們使用的也不多。
根據(jù)服務(wù)器的配置,我們也可以實現(xiàn)自定義 HTTP 方法,不過使用標(biāo)準(zhǔn)方法之外的自定義方法像是一場賭博,可能會給其他開發(fā)者設(shè)置一些潛在的限制,因為他們可能會搞不懂我們的自定義方法。雖然如此,我們可以通過 WordPress 來使用任何喜歡的方法,我們將在下面簡要的介紹如何實現(xiàn)這一點。
響應(yīng)碼
HTTP 使用數(shù)字和字符串形式的響應(yīng)代碼,而不是對每一個響應(yīng)做一個冗長的解釋,這里指的是標(biāo)準(zhǔn)的響應(yīng)代碼。我們也可以在創(chuàng)建 API 的時候定義自己的響應(yīng)代碼,但是除非需要支持特定類型的響應(yīng),我們最好遵循標(biāo)準(zhǔn)代碼,自定義代碼通常在 1xx 范圍內(nèi)。
響應(yīng)代碼類型
響應(yīng)類型可以通過響應(yīng)代碼最左邊的數(shù)字看到。
| 狀態(tài)碼 | 描述 |
|---|---|
| 2XX | 請求成功 |
| 3XX | 請求被重定向到另一個URL |
| 4XX | 請求失敗,由于客戶端錯誤。通常無效的驗證或丟失的數(shù)據(jù) |
| 5XX | 由于服務(wù)器錯誤,請求失敗。通常丟失或錯誤配置的配置文件 |
通用代碼
下面是我們最常遇到的響應(yīng)代碼。
| 狀態(tài)碼 | 描述 |
|---|---|
| 200 | 請求成功 |
| 301 | 資源被永久移動 |
| 302 | 資源暫時移動 |
| 403 | 禁止 – 通常由于驗證無效 |
| 404 | 資源未找到 |
| 500 | 內(nèi)部服務(wù)器錯誤 |
| 503 | 暫停服務(wù) |
從 API 獲取數(shù)據(jù)
Github 提供了一個非常優(yōu)秀的 API,不需要注冊就可以訪問一些公開數(shù)據(jù),所以,為了演示上面提到的一些方法,我們將訪問 GIthub API 進(jìn)行演示。
通過 wp_remote_get() 函數(shù)獲取數(shù)據(jù)在 WordPress 中非常簡單,這個函數(shù)接受以下兩個參數(shù)。
- $url – 資源的 URL 地址,必須使用標(biāo)準(zhǔn)的 HTTP URL 格式
- $args – 可選,我們可以在這里傳遞一個參數(shù)數(shù)組來改變請求的行為和 header 信息,例如 cookies,重定向等。
下面是 $args 參數(shù)的一些默認(rèn)值,我們可以通過 $args 參數(shù)設(shè)置這些值。
- method – GET
- timeout – 5 –放棄之前的等待時間
- redirection – 5 – 跳轉(zhuǎn)之前的等待時間
- httpversion – 1.0
- blocking – true – 頁面的其他部分是否需要等待此操作完成之前才能加載
- headers – array()
- body – null
- cookies – array()
下面,讓我們獲取一個 Github 賬戶的 URL,看看可以得到什么樣的信息。
$response = wp_remote_get( 'https://api.github.com/users/blobaugh' );
$response 將包含有關(guān)我們請求的所有 headers 信息,內(nèi)容和其他元數(shù)據(jù)。
Array (
[headers] => Array (
[server] => nginx
[date] => Fri, 05 Oct 2012 04:43:50 GMT
[content-type] => application/json; charset=utf-8
[connection] => close
[status] => 200 OK
[vary] => Accept
[x-ratelimit-remaining] => 4988
[content-length] => 594
[last-modified] => Fri, 05 Oct 2012 04:39:58 GMT
[etag] => 5d5e6f7a09462d6a2b473fb616a26d2a
[x-github-media-type] => github.beta
[cache-control] => public, s-maxage=60, max-age=60
[x-content-type-options] => nosniff
[x-ratelimit-limit] => 5000
)
[body] => {type:User,login:blobaugh,gravatar_id:f25f324a47a1efdf7a745e0b2e3c878f,public_gists:1,followers:22,created_at:2011-05-23T21:38:50Z,public_repos:31,email:[email protected],hireable:true,blog:http://ben.lobaugh.net,bio:null,following:30,name:Ben Lobaugh,company:null,avatar_url:https://secure.gravatar.com/avatar/f25f324a47a1efdf7a745e0b2e3c878f?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png,id:806179,html_url:https://github.com/blobaugh,location:null,url:https://api.github.com/users/blobaugh}
[response] => Array (
[preserved_text 5237511b45884ac6db1ff9d7e407f225 /] => 200
[message] => OK
)
[cookies] => Array()
[filename] =>
)
所有相同的輔助函數(shù)都可以像上面演示的一樣使用,并且返回類似的信息,但是 HEAD 方法除外,因為這個方法永遠(yuǎn)不會返回 body 信息。
獲取 Body 信息
通常我們只需要使用響應(yīng)的 body 信息,我們可以使用 wp_remote_retrieve_body() 來獲取這個信息,這個函數(shù)只需要一個參數(shù),就是其他 wp_remote_X 函數(shù)的響應(yīng),其中 retrieve 不是下一個值。
$response = wp_remote_get( 'https://api.github.com/users/blobaugh' );
$body = wp_remote_retrieve_body( $response );
比如我們獲取前面例子中的 Github 資源,獲取到的 $body 信息為:
{type:User,login:blobaugh,public_repos:31,gravatar_id:f25f324a47a1efdf7a745e0b2e3c878f,followers:22,avatar_url:https://secure.gravatar.com/avatar/f25f324a47a1efdf7a745e0b2e3c878f?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png,public_gists:1,created_at:2011-05-23T21:38:50Z,email:[email protected],following:30,name:Ben Lobaugh,company:null,hireable:true,id:806179,html_url:https://github.com/blobaugh,blog:http://ben.lobaugh.net,location:null,bio:null,url:https://api.github.com/users/blobaugh}
如果除了獲取 body 信息之外,我們沒有其他操作,我們可以把上面的代碼壓縮為一行。
$body = wp_remote_retrieve_body( wp_remote_get( 'https://api.github.com/users/blobaugh' ) );
許多輔助函數(shù)都可以這樣使用。
獲取響應(yīng)代碼
我們可能需要檢查響應(yīng)代碼,以確保我們的請求是成功的,我們可以通過 wp_remote_retrieve_response_code() 來檢查。
$response = wp_remote_get( 'https://api.github.com/users/blobaugh' );
$http_code = wp_remote_retrieve_response_code( $response );
如果請求成功, $http_code 將包含 200。
獲取特定的 Header 信息
有時候,我們需要獲取一個特定的 Header 信息,比如數(shù)據(jù)的最后修改時間,我們可以使用 wp_remote_retrieve_header() 函數(shù)來獲取,這個函數(shù)接受兩個參數(shù)。
- $response – 來自請求的響應(yīng)信息
- $header – 要獲取 Header 信息的名稱
獲取最后修改時Header 信息
$response = wp_remote_get( 'https://api.github.com/users/blobaugh' );
$last_modified = wp_remote_retrieve_header( $response, 'last-modified' );
$last_modified 將包含 [last-modified] => Fri, 05 Oct 2012 04:39:58 GMT
我們還可以使用 wp_remote_retrieve_headers( $response ) 獲取 HTTP 響應(yīng)的所有 Header 信息。
使用 GET 進(jìn)行基本身份驗證
更安全的 API 會提供一種或多種身份驗證,HTTP 基本認(rèn)證是一種常見但不是很安全的認(rèn)證方法,我們可以在 WordPress 中使用這種認(rèn)證方法,把我們的授權(quán)信息傳遞給 wp_remote_get() 函數(shù)的第二個參數(shù)即可,其他 HTTP 方法也一樣。
$args = array(
'headers' => array(
'Authorization' => 'Basic ' . base64_encode( YOUR_USERNAME . ':' . YOUR_PASSWORD )
)
);
wp_remote_get( $url, $args );
將數(shù)據(jù)發(fā)送到 API
wp_remote_retrieve_body() 可以在所有 HTTP 方法上面以同樣的方式使用。
發(fā)送數(shù)據(jù)應(yīng)該使用 wp_remote_post() 函數(shù)完成,該函數(shù)的參數(shù)和 wp_remote_get() 完全一樣,需要注意的是,我們應(yīng)該把需要發(fā)送的所有數(shù)據(jù)放到第二個參數(shù)里面,函數(shù)提供了一些基本默認(rèn)數(shù)據(jù),我們只需要關(guān)注我們發(fā)送的數(shù)據(jù)即可。
要發(fā)送數(shù)據(jù)到服務(wù)器,我們需要建立一個關(guān)聯(lián)數(shù)組,該數(shù)組將被設(shè)置為 ‘body’ 的值,如我們所愿,在接受請求的服務(wù)端,這個數(shù)組的值將出現(xiàn)在 $_POST 變量中。舉個例子,如果 body => array( 'myvar' => 5 ),在接收服務(wù)器上就是 $_POST['myvar'] = 5 。
由于 Github 不允許發(fā)送 POST 請求到上面例子中的 API 上,下面的例子是偽造的。通常,如果需要將數(shù)據(jù)發(fā)布到 API,我們需要從 API 提供方獲取 API 密鑰或其他形式的身份驗證令牌。用來證明我們的應(yīng)用程序可以像用戶一樣登錄到服務(wù)器,通過 API 操作服務(wù)器上的數(shù)據(jù)。
比如我們正在提交一個聯(lián)系表單,其中包含 name, email, subject, comment 這些字段,我們首先需要設(shè)置 POST 請求的 body 信息。
$body = array(
'name' => 'Jane Smith',
'email' => '[email protected]',
'subject' => 'Checkout this API stuff',
'comment' => 'I just read a great tutorial by this Ben Lobaugh. It taught me amazing things about interacting with APIs in WordPress! You gotta check it out!'
);
然后,把我們設(shè)置的 $body 信息和其他可選的參數(shù)設(shè)置為 wp_remote_post() 的第二個參數(shù)。
$args = array(
'body' => $body,
'timeout' => '5',
'redirection' => '5',
'httpversion' => '1.0',
'blocking' => true,
'headers' => array(),
'cookies' => array()
);
然后,發(fā)送請求。
$response = wp_remote_post( 'http://your-contact-form.com', $args );
完整的代碼如下:
$body = array(
'name' => 'Jane Smith',
'email' => '[email protected]',
'subject' => 'Checkout this API stuff',
'comment' => 'I just read a great tutorial by this Ben Lobaugh. It taught me amazing things about interacting with APIs in WordPress! You gotta check it out!'
);
$args = array(
'body' => $body,
'timeout' => '5',
'redirection' => '5',
'httpversion' => '1.0',
'blocking' => true,
'headers' => array(),
'cookies' => array()
);
$response = wp_remote_post( 'http://your-contact-form.com', $args );
注意帶寬使用情況
在獲取資源之前,使用 HEAD 檢查資源狀態(tài)可能非常重要(有些 API 要求這樣做),在高流量的 API 上,GET 請求通常會被限制頻次,除非 HEAD 請求的返回信息顯示 API 上的數(shù)據(jù)已更新,否則不需要發(fā)送 GET 請求。
像上面說的一樣,HEAD 包含數(shù)據(jù)是否已經(jīng)更新,數(shù)據(jù)是否應(yīng)該被緩存,緩存何時過期以及有時對 API 的請求速率限制。
回到上面的 Github 示例,有幾個 Header 信息需要注意,這些 Header 信息大部分都是 HTTP 的標(biāo)準(zhǔn)信息,也有一些自定義的 Header 信息,使用之前,我們應(yīng)該檢查 API 文檔來了解每個自定義頭文件的用途。
- x-ratelimit-limit – 一段時間內(nèi)的請求限制
- x-ratelimit-remaining – 一段時間內(nèi)的剩余請求限制
- content-length – 內(nèi)容的字節(jié)長度,可以用來警告用戶內(nèi)容很大
- last-modified – 數(shù)據(jù)的最后更新時間,對緩存工具非常有用
- cache-control – 客戶端應(yīng)該怎么處理緩存
下面,我們將獲取上面 GIthub 賬戶的 HEAD 值。
$response = wp_remote_head( 'https://api.github.com/users/blobaugh' );
$response 看起來如下:
Array (
[headers] => Array (
[server] => nginx
[date] => Fri, 05 Oct 2012 05:21:26 GMT
[content-type] => application/json; charset=utf-8
[connection] => close
[status] => 200 OK
[vary] => Accept
[x-ratelimit-remaining] => 4982
[content-length] => 594
[last-modified] => Fri, 05 Oct 2012 04:39:58 GMT
[etag] => 5d5e6f7a09462d6a2b473fb616a26d2a
[x-github-media-type] => github.beta
[cache-control] => public, s-maxage=60, max-age=60
[x-content-type-options] => nosniff
[x-ratelimit-limit] => 5000
)
[body] =>
[response] => Array (
[preserved_text 39a8515bd2dce2aa06ee8a2a6656b1de /] => 200
[message] => OK
)
[cookies] => Array()
[filename] =>
)
發(fā)送任何形式的請求
如果我們需要使用和上面介不一樣的方法來發(fā)送請求,不要怕,WordPress開發(fā)團(tuán)隊已經(jīng)考慮到了這一點,并提供了 wp_remote_request() 函數(shù)來幫助我們,這個函數(shù)的參數(shù)和 wp_remote_get() 一樣,并且可以讓我們指定 HTTP 方法,需要以什么樣的請求方法傳遞什么樣的數(shù)據(jù),完全取決于我們自己。
比如,我們需要發(fā)送一個 DELETE 方法的請求。
$args = array(
'method' => 'DELETE'
);
$response = wp_remote_request( 'http://some-api.com/object/to/delete', $args );
緩存
緩存是一種很常見的實踐,我們經(jīng)常會把比較耗時的常用對象保存到一個方便快速獲取的緩存庫里面,以便在以后的請求中快速獲取。這樣可以避免服務(wù)器耗費不必要的時間重新生成重復(fù)數(shù)據(jù)。緩存是一個比較大的話題,是網(wǎng)站性能優(yōu)化的一部分,我們在這里不展開討論。下面的內(nèi)容只是對緩存的介紹,以及設(shè)置 HTTP API 響應(yīng)緩存的方法。
為什么要緩存 API 響應(yīng)呢?有時候,外部 API 會降低我們網(wǎng)站的響應(yīng)速度。我們可能會在某些地方看到,利用外部 API 可以減少連接和處理的數(shù)量、以及昂貴的帶寬,從而提高網(wǎng)站性能,但在有些情況下,會出現(xiàn)相反的情況。
我們需要在服務(wù)器發(fā)送數(shù)據(jù)的速度和請求遠(yuǎn)程數(shù)據(jù)并等待其返回所花的時間之間進(jìn)行平衡。后者顯而易見的問題是許多 API 會對一段時間內(nèi)的請求數(shù)量做限制,并且可能會限制一次請求的連接數(shù)量。緩存可以把獲取到的遠(yuǎn)程數(shù)據(jù)副本放到我們自己的服務(wù)器上,從而解決這些問題,直到數(shù)據(jù)需要刷新為止。
應(yīng)該什么時候進(jìn)行緩存?
答案是,大多數(shù)情況下,我們都應(yīng)該進(jìn)行緩存,除非我們需要處理的是實時數(shù)據(jù),或者 API 的 HEAD 信息明確指定了不緩存數(shù)據(jù)。
WordPress 的緩存 API
WordPress 緩存 API 為我們提供了一種方便的方式來存儲和使用緩存,緩存有一段時間的有效期,過了有效期或遠(yuǎn)程 API 中的數(shù)據(jù)更新了之后,我們需要重新設(shè)置緩存,WordPress 的緩存功能可能是最方便使用的緩存系統(tǒng)了,緩存 API 只提供了三個功能來幫助我們完成繁雜的工作。
設(shè)置緩存
我們使用 set_transient 函數(shù)來緩存一個對象,該函數(shù)接受以下三個參數(shù):
- $transient – 緩存的名稱,供獲取和刪除緩存使用
- $value – 緩存的值
- $expiration – 緩存的到期時間
下面的代碼把從 Github API 中獲取的用戶信息緩存了一個小時。
$response = wp_remote_get( 'https://api.github.com/users/blobaugh' );
set_transient( 'blobaugh_github_userinfo', $response, 60*60 );
獲取緩存
獲取緩存對象要比設(shè)置緩存復(fù)雜一點,在獲取緩存之前,我們需要先檢查緩存是否已經(jīng)過期,如果已過期,我們需要從 API 獲取新數(shù)據(jù),然后重新設(shè)置緩存供下一次獲取。通常 set_transient 和 get_transient 是一起使用的。以下的是獲取 Github 用戶信息緩存的示例。
$github_userinfo = get_transient( 'blobaugh_github_userinfo' );
if( false === $github_userinfo ) {
// 緩存已過期,刷新緩存
$response = wp_remote_get( 'https://api.github.com/users/blobaugh' );
set_transient( 'blobaugh_github_userinfo', $response, 60*60 );
}
// Use $github_userinfo as you will
刪除緩存
刪除緩存就容易得多了,只需要把緩存的名稱傳遞給?delete_transient 函數(shù)就可以了。
delete_transient( 'blobaugh_github_userinfo' );