請先想像一下,不同國家的人一起坐在一場圓桌會議上,有些人說日文、有些人說英文、有些人說中文,大家雞同鴨講,無法順利溝通。這時候就可以使用一個語言,是大家都會的語言,這樣的語言就像是 protocol。
Protocol 就像是是一個格式化的標準,讓不同規格、不同語言、不同系統的系統或是平台,都能透過這樣的標準,進行資訊的流通及處理。
舉例來說,要瀏覽網站的話,要遵守網站的通訊協定,叫 http ( HyperText Transfer Protocol );而要傳輸檔案,則要遵循傳輸檔案用的 FTP ( File Transfer Protocol )。
了解網站前,先要知道網站的資訊是如何傳送的。Client 端( ex:是瀏覽器)發送HTTP Request (包含 head 跟 body)請求給 Server 端,Server 端收到後再回傳 Response 回應(包含 head 跟 body)給 Client 端。詳請可看此。
將 Domain Name 網域名稱(www.google.com)翻譯成 IP 位址。
在 terminal 上可以使用 nslookup
的指令,後面加上欲查詢 IP 位址的網域名稱,即可查詢 IP 位址。如果查詢結果是 no response from server 時,可以在 Terminal 上使用 netsh winsock reset
,再重啟電腦一次,即可順利使用 nslookup
指令。
瀏覽器是協助我們發送 request ,接收 response 的程式。透過 node.js 的 library ─ request ( Simplified HTTP client ),也可以模擬瀏覽器發送 request,步驟如下:
npm install request
指令。
const request = require('request');
request('http://www.google.com', function (error, response, body) {
console.error('error:', error); // Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log('body:', body); // Print the HTML for the Google homepage.
});
node index.js > index.html
,將 console.log 出來的 response 寫入 index.html 內。index.html
(打開此檔案),即可順利看到最後結果。request 跟 response 內都有包含 header 跟body。 header 寫的是一些額外資訊, body 寫的是主要內容。
詳細更多可以參考 MDN。
索取並顯示資訊。如顯示圖片或 html 及 css。
透過 dev tool 內可以看到 request URL。複製此 URL 並另開一個分頁去執行,所看到的畫面,就是 response。而這個背後程式所做的事情,就是瀏覽器發送了一個 get request 到這個 URL,並接收到了 response。
提交資料並請求伺服器處理。如輸入帳號密碼。
特別注意的是,get request 沒有 body, post 有。
更改並取代原先資料。
假設今天原訂單是雞腿飯 3,排骨飯 5,put 雞腿飯 2,那這樣最後的訂單會是雞腿飯 2,連排骨飯 5 都會不見。
更改指定資料。
假設今天原訂單是雞腿飯 3,排骨飯 5,patch 雞腿飯 2,那這樣最後的訂單會是雞腿飯 2,排骨飯 5,排骨飯 5 會被保留下來。
刪除資料。
回傳該 server 可支援的溝通方式。
透過 node.js 內的 library ─ http
實作 server 端。
let http = require('http'); // 引用 library: http
let server = http.createServer(handleRequest);
function handleRequest(req, res) {
console.log('request url: ', req.url);
if (req.url === '/') {
res.writeHead(200, { // 更改 response header
'info': 'index'
})
res.write('content'); // 更改 response body
res.end();
return;
}
if (req.url === '/redirect') {
res.writeHead(301, { // 'Location': '/category' // 轉址到 /category
'Location': 'https://google.com' // 轉址到 google.com
});
res.end();
return;
}
if (req.url === '/hello') {
res.writeHead(200, {
'info':('hello')
})
res.write('hello')
res.end()
return;
}
res.write(404);
res.end();
return;
}
server.listen(5000); // 監聽 5000 這個 port
node server.js
指令(執行 server)驗證是否可以傳到 client 端:
TCP / IP 是電腦網路通訊協定,分成四個層級( 應用層、傳送層、網路層、鏈結層 )。更詳細可參考鳥哥的私房菜。
圖片來源:鳥哥的私房菜
從這個協定當中可以看到 HTTP 協定〈應用層〉建立在 TCP 協定〈傳送層〉上,而 TCP 協定又建立在 IP 位址〈網路層〉上。
IP 全名為 Internet Protocol,中文為「 網際網路協定 」。
協定也有分版本,分別是 IPv4(Internet Protocol version 4) 跟 IPv6(Internet Protocol version 6)。IPv6 可用的地址更多,解決主要 IPV4 不夠用的問題,兩者的地址也完全不同。更多差異請看這。
IP 也有分成固定 IP、虛擬 IP、浮動 IP。
圖片來源:Huli 課程內容
這樣改變位址的數據機我們稱為 NAT,底下會在更仔細的討論 。
想要查詢自己對外的 IP 位址,可以使用「 myip 」作為關鍵字,許多網頁都有提供這樣的服務使用。
NAT,Network Address Translation,網路位址轉譯。
剛開始是為了解決 IPv4 位址不夠的的問題,而想出的一個過渡期解決辦法。目前主要的用途是有三:
備註:其實有個東西叫做負載平衡器(Load Balancer),是一個軟體程式,主要就是在負責 load balance,詳細可參考 文章一 及 文章二
為了區分並接收同個電腦( IP 位址 )的不同服務,所以就有了 Port 。 在剛剛的實作一個 server 端所輸入的server.listen(5000);
,這邊的 5000 就是一個 port。
預設的 port 有 HTTP (80)、HTTPS (443)、FTP (21)。常見的測試值為 3000、4000、4001。
TCP 與 UDP 都是傳送層中的兩個協議。
大部分的網路協定都是建立在 TCP 上,因為 TCP 較為可靠、會透過「三次握手」確保資料送達。
而 UDP 重點在於速度,在日常網路應用上像是視訊或是轉播時,重點在於傳送速度而不是傳送穩定,因為漏了一兩個封包其實對使用者並不會有明顯的影響。
何謂三次握手?
三次握手又稱三路握手,全名為 threee-way handshake。簡單來說 client 端跟 server 端會通過三次的聯繫來確保資訊有確實傳達給對方。
圖片來源:由 原上傳者為中文維基百科的Huage.chen - Transferred from zh.wikipedia to Commons by Shizhao using CommonsHelper., CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=36967543
層級內容 | 層級用義 | 紙條故事 |
---|---|---|
HTTP / FTP | 傳輸內容 | 紙條內容 |
TCP / UDP | 傳輸方式 | 三次確認 / 講求速度 |
IP | 傳輸地址 | 寄件人和收件人 |
實體層 | 實體傳輸 | 郵差 |
這裡的伺服器並非指的是像 Apache(Web Server)、FTP Server 這類管理伺服器的軟體。
這裡的伺服器指的是執行上述各種伺服器管理軟體的主機,伺服器管理軟體可能還包含 DNS Server、Mail Server、Database Server 等。通常具備較高的計算能力、能夠提供給一個或多個使用者使用的電腦/主機。
伺服器常見有三個種類:
常見管理的方式有兩種:
ssh + ip位址
,連線成功後可以使用 top
確認主機效能。Virtual Private Network,虛擬私人網路。根據維基百科,VPN 是一種常用於連接中、大型企業或團體與團體間的私人網路的通訊方法。 它利用隧道協定(Tunneling Protocol)來達到傳送端認證、訊息保密與準確性等功能。
概念基本上就像是先連到一個主機,再由那個主機連線到其他地方。常見的應用:
全名為 Application Programming Interface,中文翻譯為「應用程式介面」。簡單來說透過 API 就是一個交換資料的工具。
API 有分很多種,這邊會提到的是基於 HTTP 協定下的 Web API (HTTP API)。
API 常見的 CRUD 功能分別指的是:新增(Create)、讀取(Read)、更新(Update)、刪除(Delete),有時候會聽到五項功能,多了一個列表(List)。
有個簡單提供測試是否可以串接成功的 API 網站 ─ Regres。透過此網站下方 jQuery 內提供的 URL,放入測試程式碼內,即可實測。
const request = require('request');
request('https://reqres.in/api/users', function (error, response, body) {
console.log( body); // Print the HTML for the Google homepage.
});
在 URL 後方也可以加上欲加入的物件,像是https://reqres.in/api/users/2, 即可呈現 ID :2 的元素。
若是想要在 Terminal 上直接執行 node index.js 2
,可以另外在檔案內加入const process = require('process');
,並可以先用console.log
測試 process 到底是甚麼。
在 terminal 上執行 node index.js 2
,就會發現顯示出來的結果是。
第一行顯示的結果表示,node 位置。
第二行顯示的結果表示,index.js 位置。
第三行顯示的結果表示,2。
process.argv[2] 作為一個陣列,欲取第三個元素。並將此放在 URL 後。範例碼如下:
const request = require('request');
const process = require('process');
request(
'https://reqres.in/api/users/' + process.argv[2],
function (error, response, body) {
console.log(body);
}
);
這時候如果在 Terminal 內中執行 node index.js 2
,即可順利顯示 ID 2 的內容,執行 node index.js 3
,也可順利顯示 ID 3 的內容。
透過之前有提到的 request library 的 Github 網頁,點選 forms,並使用之前所提到的 reqres 將相關資料填入。
const request = require('request');
const process = require('process');
request.post(
{
url:"https://reqres.in/api/users",
form: {
name:'shelly',
job: 'none'
}
},
function (error, response, body) {
console.log(body);
}
);
執行 node index.js
也可成功寫入資料(這邊只是測試用,所以並不會真正寫入資料)。
該如何實際執行 API 的 GET、POST、PATCH、DELETE…等指令呢?可以透過之前提到的 request 官方文件,並 ctrl + F 找關鍵字「request.METHOD()」,找到如何使用的方法。
以下實作 DELETE 跟 PUT。
依照官網在所提供的語法(request.delete
),以下提供範本。
const request = require('request');
const process = require('process');
request.delete(
"https://reqres.in/api/users/2",
function (error, response, body) {
const json = JSON.parse(body);
console.log(json);
}
);
執行後會發現沒跑出任何 response。這時候我們可以在第六、七行之間加上console.log('body:', body)
,確認 body 內容。執行後發現 body 是空的。
這時候我們可以再透過印出 status code 確認狀態。透過console.log(response.statusCode)
回傳的結果是 204 。表示是成功的,只是沒有內容(因為已經刪除完畢)。
與 POST 運用的格式相同,範例如下:
const request = require('request');
const process = require('process');
request.patch(
{
url:'https://reqres.in/api/users',
form: {
Name:'Shell'
}
},
function (error, response, body) {
console.log(body);
}
);
RESTful 是一種風格,該如何形容這個風格呢?就是一種語意化、更為嚴謹的描述 API 方式,目前也是最常見的方式。
本圖片源自 Huli 上課教材。
在最左邊的一欄當中是要做的事情,左二是欲使用的指令,取而代之咖啡色字體的是 RESTful 風格的指令,右二是非 RESTful 風格的寫法,右一是 RESTful 風格的寫法。
所以可以看到 RESTful 的寫法較為一致、也更好理解。
這篇簡報有更仔細地談甚麼是 RESTful API。
之前我們提到的發送或是回傳的資料,都是有格式的。這些在電腦科學中,資料格式是電腦中儲存、傳輸資料的方式。
資料格式可以簡略分成三種:純文字與自定義格式、XML、JSON。
直接透過文字跟條件式定義格式。
全名是 Extensible Markup Language,中文是可延伸性標記式語言。XML 跟 HTML 一樣,都是屬於 Markup Language 標記式語言,均透過前後的標籤來包覆住內容。這裡可參考更多 XML 入門文件。
以前傳輸資料經常使用 XML,現在多數人都使使用 JSON。
全名是 JavaScript Object Notation ,中文是 JavaScript 物件表示法。依照維基百科,是一種輕量級的資料交換語言,該語言以易於讓人閱讀的文字為基礎,用來傳輸由屬性值或者序列性的值組成的資料物件。
雖然 JSON 稱之為 JavaScript 物件表示法,但是這個資料格式被廣泛的以函式庫的方式,用在其他語言當中。
JSON 所需要的儲存空間相較 XML 少上許多,所以目前 JSON 是最普遍被使用的資料格式。
在程式判讀上 XML 相較另一個資料格式 JSON 需要花費更多時間耗費資源。更多兩個資料格式的比較,可以看 JSON與XML優缺點對比分析 。
之前實作 API 時所回傳的格式,就是 JSON 格式。
const request = require('request');
const process = require('process');
request(
"https://reqres.in/api/users/2",
function (error, response, body) {
console.log(body);
}
);
回傳的 response 如以下:
{"data":{"id":2,"email":"janet.weaver@reqres.in","first_name":"Janet","last_name":"Weaver","avatar":"https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128.jpg"}}
這個回傳的格式,就是一個 JSON 格式的 string。這樣的 String 比較難像物件一樣直接存取物件的 key 。那我們可以透過內建函式JSON.parse()
,將 string 改成物件格式。
將上面的console.log(body)
改成console.log(JSON.parse(body))
。回傳的 response 則會變成以下:
{ data:
{ id: 2,
email: 'janet.weaver@reqres.in',
first_name: 'Janet',
last_name: 'Weaver',
avatar:
'https://s3.amazonaws.com/uifaces/faces/twitter/josephstein/128.jpg' } }
那如果是物件格式想要改成 JSON 格式的 string ,可以使用 JSON.stringify()
。
SOAP 全名為 Simple Object Access Protocol ,中文是簡單物件存取協定。一種基於 XML 的交換資料協議規範。
目前已經很少人在使用,大多人都是使用 HTTP API,也就是我們上方所提到且實測的。
curl 指令操作簡單、在 terminal 就可以發送 request (需下載)。除了支援 HTTP request 之外,還可以上傳跟下載檔案。以下會簡單介紹幾種常用的 curl 指令,更多可以看 TechBridge 的介紹文章及另一篇文章,寫得非常淺顯易懂。
curl [options] [URL..]
curl [URL]
curl [URL] > index.html
。就下載此 response 到 index.html 裡。curl -I [URL]
curl -- head [URL]
這邊有一篇文章非常簡單的說明了如何使用 curl 做 http 的測試。
ping [Url]
測試後方放入的網址是否可順利連結上。
telnet [URL] [Port]
查詢是否可以連接到指定的 port。
剛開始無法使用,參考了這篇文章 ,解決了第一步無法使用。
經由 telnet 連到 IP 位址的 port 後,可以輸入「get/」就會取得 GET request 的資料。其它指令也是可以直接操作。
補充現狀:剛先透過 nslookup
查詢 google.com 的 IP 位址,再透過 telnet
查詢 port。但目前還是似乎無法使用 telnet
的指令,可使用的指令是 telnet ptt.cc
。
基本上按照串接 TWITCH API 的教學文件即可,但我還是遇到非常多的問題。這邊紀錄幾個非常耗費我耐心與腦力的問題,避免之後再犯:
curl: (6) Could not resolve host:
和 curl: (1) Protocol "'https" not supported or disabled in libcurl
的問題解法:裡面的單引號('')全數都要換成雙引號("")。參考資料:單引號換雙引號
可參考保哥的影片。
HTTP Request
、API