リクエスト数によるアクセス制限の対策方法

※本制限は2021年11月17日(水)より適用されます。※

<アクセス制限について>

請求ロボのAPIでは同一IPアドレスから5分間に300回を超えるリクエストをすると、
一定時間アクセス制限がかかります。
ここでは、アクセス制限を予防する方法やその対策について紹介します。

サンプルコードでは 請求書参照2 (https://apispec.billing-robo.jp/public/bill/search_list2.html) を例に説明します。
言語はNode.jsで記述しています。

<アクセス制限を予防する実装>

方法1、方法2両方の実装をする事を推奨します。

方法1:配列を利用してリクエスト回数を減らす

「請求書参照2」APIで請求書番号 bill-number-01, bill-number-02, bill-number-03 の情報を取得する際に
3回リクエストをするのではなく、配列にしてリクエスト回数を1回にしています(L14〜L34)。

Request Bodyのサイズが9Mbyteを超過した場合はエラーとなるため、同時にエラーハンドリングの
 実装を推奨します。詳細については後述の「アクセス制限の検知方法」を参照ください。

// axiosモジュールの設定
const axiosBase = require('axios');
const axios = axiosBase.create({
  baseURL: 'https://billing-robo.jp:10443',
  headers: {
    'Content-Type': 'application/json',
  },
  responseType: 'json'
});

// APIリクエストを実行する関数
const execApiRequest = async () => {
  // リクエスト内容の作成(配列にしてリクエスト回数を1回にする)
  const requestBody = JSON.stringify({
    "user_id": "sample@robotpayment.co.jp",
    "access_key": "xxxxxxxxxxxxxxxx",
    "bill": [
      {
        "number": "bill-number-01",
        "issue_start_date": "2021/06/01",
        "issue_stop_date": "2021/06/30"
      },
      {
        "number": "bill-number-02",
        "issue_start_date": "2021/06/01",
        "issue_stop_date": "2021/06/30"
      },
      {
        "number": "bill-number-03",
        "issue_start_date": "2021/06/01",
        "issue_stop_date": "2021/06/30"
      }
    ]
  })

  // APIリクエスト
  try {
    response = await axios.post('/api/v1.0/bill/search_list2', requestBody);
    console.log(JSON.stringify(response.data));
  } catch (error) {
    console.log(error.response.data);
  }
}

// リクエストの実行
execApiRequest();

方法2:インターバル時間を設ける

「方法1:配列を利用してリクエスト回数を減らす」が処理の都合上困難である場合、連続的にリクエストをする際はL38のように、最低1秒以上のインターバルを空けてリクエストをしてください。
この時の処理は同期処理としてください。

// axiosモジュールの設定
const axiosBase = require('axios');
const axios = axiosBase.create({
  baseURL: 'https://billing-robo.jp:10443',
  headers: {
    'Content-Type': 'application/json',
  },
  responseType: 'json'
});

// APIリクエストを実行する関数
const execApiRequest = async () => {
  // 取得対象の請求書番号
  const bill_numbers = ["bill-number-01", "bill-number-02", "bill-number-03"];
  // 請求書番号の数だけ繰り返し
  for (bill_number of bill_numbers) {
    // リクエスト内容の作成
    const requestBody = JSON.stringify({
      "user_id": "sample@robotpayment.co.jp",
      "access_key": "xxxxxxxxxxxxxxxx",
      "bill": [
        {
          "number": bill_number,
          "issue_start_date": "2021/06/01",
          "issue_stop_date": "2021/06/30"
        }
      ]
    });

    // APIリクエスト
    try {
      response = await axios.post('/api/v1.0/bill/search_list2', requestBody);
      console.log(JSON.stringify(response.data));
    } catch (error) {
      console.log(error.response.data);
    }
    // 1秒のインターバル
    await new Promise(resolve => setTimeout(resolve, 1000));
  }
}

// リクエストの実行
execApiRequest();


<アクセス制限の検知方法>

前述のアクセス制限の対策を行っても、他の処理が同時に動いた結果意図せずにリクエスト数が増加してアクセス制限がかかる事が想定されます。

他にも「方法1:配列を利用してリクエスト回数を減らす」対応でリクエストサイズが大きくなりすぎてリクエストに
失敗するケースもあります。

ここではアクセス制限にかかった時の検知方法を紹介します。

  1. リクエスト数によるアクセス制限の対象となるとレスポンスのステータスコードが 429 Too Many Requests
    となります。L32のようにステータスコードの判定を行ってください。
  2. リクエストサイズ制限の対象となるとレスポンスのステータスコードが
    413 Request Entity Too Largeとなります。L41のようにステータスコードの判定を行ってください。
// axiosモジュールの設定
const axiosBase = require('axios');
const axios = axiosBase.create({
  baseURL: 'https://billing-robo.jp:10443',
  headers: {
    'Content-Type': 'application/json',
  },
  responseType: 'json'
});

// APIリクエストを実行する関数
const execApiRequest = async () => {
  // リクエスト内容の作成
  const requestBody = JSON.stringify({
    "user_id": "sample@robotpayment.co.jp",
    "access_key": "xxxxxxxxxxxxxxxx",
    "bill": [
      {
        "number": "bill-number-01",
        "issue_start_date": "2021/06/01",
        "issue_stop_date": "2021/06/30"
      }
    ]
  });

  // APIリクエスト
  try {
    response = await axios.post('/api/v1.0/bill/search_list2', requestBody);
    console.log(JSON.stringify(response.data));
  } catch (error) {
    // エラーハンドリング
    if (error.response.status === 429) {
      // 429 Too Many Requestsの判定
      console.log('リクエスト数によるアクセス制限中のため処理を中断します');
      console.log('失敗したリクエスト内容');
      console.log('===========');
      console.log(requestBody);
      console.log('===========');
      // 異常終了(処理を中断)
      process.exit(1);
    } else if (error.response.status === 413) {
      // 413 Request Entity Too Largeの判定
      console.log('リクエストサイズが一定数を越えたため、アクセスが拒否されました');
      console.log('失敗したリクエスト内容');
      console.log('===========');
      console.log(requestBody);
      console.log('===========');
      // 異常終了(処理を中断)
      process.exit(1);
    } else {
      console.log('リクエストに失敗しました');
      console.log(error.response.data);
      console.log('失敗したリクエスト内容');
      console.log('===========');
      console.log(requestBody);
      console.log('===========');
      // 異常終了(処理を中断)
      process.exit(1);
    }
  }
}

// リクエストの実行
execApiRequest();


ステータスコード別の対処方法

429 Too Many Requests となった場合

APIリクエストを中断し、2分程度時間を置いてから必要に応じて失敗したAPIリクエストのリトライを行ってください。

413 Request Entity Too Large となった場合

APIリクエストのレコード件数を減らして、リクエストサイズを小さくしたうえでAPIリクエストのリトライを
行ってください。

<解決が困難な場合>

前述の対応を行ってもアクセス制限となり業務に支障をきたす場合はお問い合わせください。