使用 curl 工具進行簡單的 http 測試

很常看見大家用 curl 在測試 http 伺服器或一些 REST API endpoints,這篇廢文的重點就小小地來介紹一下 curl 這個工具,順便用 node 的 http server 做一些廢廢的範例來測試一下。

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}


      結語

      好啦!終於結束這篇廢廢的文章了.... chrome 也有 postman 的外掛可以用啦~ 哈哈哈.... 


       
       
       
      simen

      An enthusiastic engineer with a passion for learning. After completing my academic journey, I worked as an engineer in Hsinchu Science Park. Later, I ventured into academia to teach at a university. However, I have now returned to the industry as an engineer, again.

      1 Comments

      Post a Comment
      Previous Post Next Post