很常看見大家用 curl 在測試 http 伺服器或一些 REST API endpoints,這篇廢文的重點就小小地來介紹一下 curl 這個工具,順便用 node 的 http server 做一些廢廢的範例來測試一下。
它支援很多協定,包含 FTP, HTTPS, HTTP, Telnet, TFTP 等,官網列出了很詳細的清單,有興趣者可到官網給它瞄個幾眼~ 然後 manual 在這裡,挑一下常用的使用方式來看看:
如果你的系統沒有 curl,記得安裝一下
curl
官網這麼說:curl is used in command lines or scripts to transfer data.
它支援很多協定,包含 FTP, HTTPS, HTTP, Telnet, TFTP 等,官網列出了很詳細的清單,有興趣者可到官網給它瞄個幾眼~ 然後 manual 在這裡,挑一下常用的使用方式來看看:
- 發 request 到 http 或 ftp 伺服器
$ curl http://www.example.com:port
$ curl ftp://www.example.com:port
- 如果要帳號密碼 (-u)
$ curl -u name:passwd http://xxx.xxx.xxx:port/path/to/endpoint
$ curl -u name:passwd ftp://xxx.xxx.xxx:port/path/to/file
- 取回來的東西存成檔案 (-o)
$ curl -o filename http://xxx.xxx.xxx:port/path/to/endpoint
- 以 server 端檔案名稱作為檔名儲存下來 (-O)
$ curl -O http://xxx.xxx.xxx:port/path/to/filename
如果你的系統沒有 curl,記得安裝一下
$ sudo apt-get install curl
簡單的 http server
- 又是 Hello World!:這個 server 開在 port 3000
var http = require('http'); var server = http.createServer(function (req, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('Hello from node.js\n'); }); server.listen(3000, function () { console.log('Server for curl testing'); });
- 開一個 terminal 跑 server.js
$ node server.js
- 用瀏覽器開啟 http://localhost:3000 看看
- 開另一個 terminal 用 curl 試試看
$ curl http://localhost:3000
Hello from node.js
- 用 curl 並將回傳資料存成檔案 msg.txt
$ curl -o msg.txt http://localhost:3000
$ cat msg.txt
Hello from node.js
測試首頁 index.html
- 準備一下檔案 index.html,內容如下
<!DOCTYPE html> <html> <head> <title>Curl Testing</title> </head> <body> <h1>Hello World from Node.js</h1> <div> <p>Have Fun!</p> </div> </body> </html>
- 當 client 端進來後,回傳 index.html 的內容
var http = require('http'), fs = require('fs'); var server = http.createServer(function (req, res) { fs.readFile('index.html', function (err, data) { res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(data); }); }); server.listen(3000, function () { console.log('Server for curl testing'); });
- 重新啟動 server.js,並用瀏覽器開看看
- 用 curl 試試看
$ curl http://localhost:3000
<!DOCTYPE html><html> ...
路由測試
這裡的路由測試很簡單,如果你想要建立完整的路由或 REST endpoints,建議使用 express 或 hapi 這一類的框架來協助你。因為只是要測一下 curl,我就不裝 express 啦~- 兩個路由,一個是網站的根 '/',另一個是 '/greeting'
var server = http.createServer(function (req, res) { if (req.url === '/') { fs.readFile('index.html', function (err, data) { res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(data); }); } else if (req.url === '/greeting') { res.writeHead(200, { 'Content-Type': 'text/html' }); res.end('<h1>Hello my friend!</h1>'); } else { res.writeHead(404, { 'Content-Type': 'text/html' }); res.end('<h1>404 Not Found</h1>'); } });
- 測試 http://localhost:3000/greeting,得到 Hello my friend!
- 用 curl
$ curl http://localhost:3000/greeting
<h1>Hello my friend!</h1>
測試 Query String
這是用 http GET 方法來搭 REST APIs 的方式之一,後面會再測一下 POST。我這裡 query 參數給了一個 name,參數值你可以填你的名字試試看- 這裡會用到核心模組 url 及它的 parse 方法,將 query string 解析成為物件。因為等一下/greeting 後面會加上 ?name=simen 這樣的查詢字串,所以在路由解析上,我就很簡單的使用字串的 startsWith() 方法做一下判斷,你或許可以試一下用 regex。這個在 express 的路由系統裡面會很好處理。
- 這裡把 name=simen 剖析成為一個物件 { name: 'simen' },然後回應 Hello simen! 給 client 端
var http = require('http'), url = require('url'), // <-- url module fs = require('fs'); var server = http.createServer(function (req, res) { if (req.url === '/') { // ... 略 } else if (req.url.startsWith('/greeting')) { var query = url.parse(req.url, true).query, greet = query.name ? ('<h1>Hello ' + query.name + '!</h1>') : ('<h1>Hello my friend!</h1>'); res.writeHead(200, { 'Content-Type': 'text/html' }); res.end(greet); } else { // ... 略 } });
- 測試 http://localhost:3000/greeting?name=simen,得到 Hello simen!
- 改用 curl
$ curl http://localhost:3000/greeting?name=simen
<h1>Hello my simen!</h1>
傳 json 字串看看
JSON 資料也是很常見的 Client/Server 互動的數據格式,這邊我也來測試一下下。這裡的 URI 端點名稱就叫 /endpoint 好了。- 傳出的 MIME type 設定為 application/json
var server = http.createServer(function (req, res) { if (req.url === '/') { // ... 略 } else if (req.url.startsWith('/greeting')) { // ... 略 } else if (req.url === '/endpoint') { var data = { name: 'simen', age: 38 }; res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(data)); } else { // ... 略 } });
- 測試 http://localhost:3000/endpoint
- 用 curl
$ curl http://localhost:3000/endpoint
{"name":"simen","age":38}
測試 POST
我們等一下要用 curl -d 以 POST 發 request 到 server 端。我要拿 POST 過來的數據,讓我年輕 20 歲 XDDD- 這裡會用到 querystring 這個模組來幫忙,先 npm install 一下。因為 POST 發過來的資料會在 body 而不是在 http header 中,而 req 本身是 stream,所以我們要監聽 'data' 事件把資料都收下來。在 'end' 事件發生時,表示資料都收完了,我們再請 querystring 這個模組幫我們剖析一下 body。 (如果你是用 express,那麼 body-parser 這個 middleware 會是你的好朋友!)
- 我會從 client 端用 POST 發一個 minus 的參數,給它的值是 20,然後在 server 端把我的年紀減掉 20 歲再發回 client 端 (很蠢的範例我知道....)
- 程式裡面走到 '/endpoint' 這裡路由中,再判斷一下發過來的 request 是 GET 還是 POST,如果是 post 就把 body 剖析一下
var http = require('http'), url = require('url'), fs = require('fs'); var qs = require('querystring'); var server = http.createServer(function (req, res) { if (req.url === '/') { // ... 略 } else if (req.url.startsWith('/greeting')) { // ... 略 } else if (req.url === '/endpoint') { var data = { method: 'unknown', name: 'simen', age: 38 }, receivedData = ''; if (req.method === 'GET') { data.method = 'GET'; res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(data)); } else if (req.method === 'POST') { data.method = 'POST'; req.on('data', function (chunk) { receivedData += chunk; }).on('end', function () { var body = qs.parse(receivedData); data.age -= body.minus; res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(data)); }); } } else { // ... } });
- 這裡我直接用 curl,懶得在 client 端畫表單了。POST 資料必須是 urlencoded 的字串,我這裡的字串很簡單 "minus=20"。試一下,YA~ 我變 18 歲了 (眾毆....)
$ curl -d "minus=20" http://localhost:3000/endpoint
{"method":"POST","name":"simen","age":18}
讚!
ReplyDelete