[Node.js] HTTP通信を行い外部サーバのファイルを取得する - request

Node.jsで外部とHTTPで通信を行います。 標準モジュールでも頑張ればもちろん可能ですが、ちょっと大変なので今回はrequestモジュールを利用してサクッと作ります。もちろん外部サーバからファイルを取得する以外にも、RESTful APIを利用するなどHTTPの上で行われる様々なことに利用できます。

github.com

requestモジュールでHTTP通信

準備

適当なディレクトリ作成しnpmでインストールします。

$ mkdir myrequest && cd myrequest
$ npm init
$ npm install request

利用方法

基本的な利用方法

以下の通りです。第1引数にURL、第2引数にコールバック用の関数を渡すだけ。これでGETによる通信が行えます。

const request = require('request');

request('http://miku3.net/', (error, response, body) => {
  // エラーチェック
  if( error !== null ){
    console.error('error:', error);
    return(false);
  }

  // レスポンスコードとHTMLを表示
  console.log('statusCode:', response && response.statusCode);
  console.log('body:', body);
});

実行してみます。正常に通信ができれば以下のようにステータスコードとレスポンスボディを表示します。

$ node test1.js
statusCode: 200
body: <!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
()

SSLで通信するには?

ここでは暗号化されていないhttpでリクエストを送りましたが、URLのschema部分をhttpsにすれば特に何もしなくてもSSLでの通信を行うことができます。

const request = require('request');
request('https://miku3.net/', (error, response, body) => {  //HTTP"S"にした
  // 通常通り処理を行う
});

クエリー文字列を追加する

リクエストするURLの後ろに?foo=1234などと直接書いても良いのですが、以下のようにハッシュを渡すだけでかんたんに付与することができます。

const request = require('request');

// クエリーを準備
const formData = {
  message: "HelloWorld",
  date: "2019-12-20"
};

request({url:'http://localhost:3000/', qs:formData}, (error, response, body) => {
  // 実際の処理
});

メソッドを指定する1 - request()

大きく2種類の方法が用意されています。まずはrequest()のオプションにmethodを追加する方法です。以下のコードでPOSTメソッドでの通信を行うことができます。

const request  = require('request');
const formData = {
  message: "HelloWorld",
  date: "2019-12-20"
};

// POSTメソッド
request({url:'http://localhost:3000/', method:"POST", form:formData}, (error, response, body)=>{
    // 通常の処理
});

値としてはGET, POST, PUT, PATCH, DELETE, HEAD, OPTIONSの指定が可能です。未指定の場合はGETです。

メソッドを指定する2 - request.get(), request.post() ...

もう一つの方法として、メソッド毎に以下のような便利関数が利用できます。

メソッド 関数
GET request.get()
POST request.post()
PUT request.put()
PATCH request.patch()
DELETE request.del(), request.delete()
HEAD request.head()
OPTIONS request.options()

実際の使い方もこれまでと同様です。以下のコードでPOSTメソッドによる通信が行えます。

const request  = require('request');
const formData = {
  message: "HelloWorld",
  date: "2019-12-20"
};

// POSTメソッド
request.post({url:'http://localhost:3000/', form:formData}, (error, response, body)=>{
    // 通常の処理
});

リクエストヘッダー

リクエストヘッダーに様々な情報を追加することができます。以下ではUserAgentを送信しています。

const request  = require('request');
const options = {
  url: 'http://localhost:3000/',
  method: 'GET',
  headers: {
    'User-Agent': 'Node.js Request Client'
  }
};

request(options, (error, response, body)=>{
    // 通常の処理
});

同様の方法でREFERERなどその他の値を送信することも可能です。

挙動を確認する

リダイレクト

サーバがLocationヘッダなどでリダイレクトする場合、自動的にリダイレクト先の内容を返してくれます。

実験してみます。以下のような簡易的なWebサーバを用意しました。

const express = require('express');
const app = express();

// ルートにアクセスしたら/moveへリダイレクト
app.get('/', (req, res) => {
  res.redirect(301, '/move');
});

// welcome
app.get('/move', (req, res) => {
  res.send("<h1>Welcome</h1>");
});

// Webサーバ起動
app.listen(3000, ()=> {
  console.log("Listening: 3000");
});

ルートへアクセスするとリダイレクト先の情報を自動的に取得してくれました。ステータスコードは300番台ではなくもちろん200です。

$ node test1.js
statusCode: 200
body: <h1>Welcome</h1>

400, 500番台のエラー

サーバ由来のエラー、もしくはファイルが存在しない場合やパーミションや認証等クライアント由来でアクセスできない場合、 requestはエラーとはしません。何が発生したかはstatusCodeに値が入るのでチェックします。

$ node test1.js
statusCode: 404
body: <!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
()

ドメインを間違えた場合

TLDをわざと1文字削ってリクエストしてみました。名前解決時にエラーになっているのがわかります。

$ node test1.js
error: Error: getaddrinfo ENOTFOUND miku3.ne
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:60:26) {
  errno: 'ENOTFOUND',
  code: 'ENOTFOUND',
  syscall: 'getaddrinfo',
  hostname: 'miku3.ne'
}

オフラインの場合

PCから試していますがWiFiを切って実行すると、やはり名前解決でコケて終わるようです。特にオンラインかどうかの判定はされていない模様。

$ node test1.js
error: Error: getaddrinfo ENOTFOUND miku3.net
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:60:26) {
  errno: 'ENOTFOUND',
  code: 'ENOTFOUND',
  syscall: 'getaddrinfo',
  hostname: 'miku3.net'
}

Primise対応のrequest

requestモジュールは基本的に非同期処理となります。Promiseに対応した同期処理を行うには別のモジュールを利用します。詳しくは以下の記事を参照ください。 blog.katsubemakito.net

参考ページ