Help us understand the problem. What is going on with this article?

JScriptでaxiosを使う

More than 3 years have passed since last update.

JavaScriptのXHRライブラリにaxiosがあります。
axiosはPromiseが使えるので個人的に好きです。

JSCriptでもXHRが使えるのですが、そのままではaxiosを使うことができません。
なので今回はaxiosを少しカスタマイズして、JScriptからでも使えるようにしてみました。
babelを使ってES2015でJScriptを書こうなどを参考にJScriptでPromiseが使えるようにしておいてください。
Promiseのpolyfillを使ってもできるかもしれません。(未検証)

カスタムアダプタの設定

axios.createを呼ぶことで、カスタマイズした設定を反映したインスタンスを生成することができます。
axiosはadapterと呼ばれるモジュールで実際の通信を行います。
設定のadapterにカスタマイズしたadapterを指定すると、通信時に優先的に呼ばれるようになります。

以下のコードはaxios v0.13のlib/adapters/xhr.jsをベースに改変しています。
カスタムアダプタの仕様が変わると使えなくなるかもしれません。

hoge.js
var axios = axios.create({
  adapter: function(config) {
    return new Promise(function dispatchXhrRequest(resolve, reject) {
      var requestData = config.data;
      var requestHeaders = config.headers;

      if (utils.isFormData(requestData)) {
        delete requestHeaders['Content-Type']; // Let the browser set it
      }

      var request = new ActiveXObject('MSXML2.ServerXMLHTTP');

      // HTTP basic authentication
      if (config.auth) {
        var username = config.auth.username || '';
        var password = config.auth.password || '';
        requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password);
      }

      try {
        request.open(config.method.toUpperCase(), buildURL(config.url, config.params, config.paramsSerializer), true);

        // Listen for ready state
        request.onreadystatechange = function handleLoad() {
          if (!request || (request.readyState !== 4)) {
            return;
          }

          // The request errored out and we didn't get a response, this will be
          // handled by onerror instead
          if (request.status === 0) {
            return;
          }

          // Prepare the response
          var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
          var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.responseBody;
          var response = {
            data: responseData,
            // IE sends 1223 instead of 204 (https://github.com/mzabriskie/axios/issues/201)
            status: request.status === 1223 ? 204 : request.status,
            statusText: request.status === 1223 ? 'No Content' : request.statusText,
            headers: responseHeaders,
            config: config,
            request: request
          };

          settle(resolve, reject, response);

          // Clean up request
          request = null;
        };

        // Add xsrf header
        // This is only done if running in a standard browser environment.
        // Specifically not if we're in a web worker, or react-native.
        if (utils.isStandardBrowserEnv()) {
          var cookies = require('axios/lib/helpers/cookies');

          // Add xsrf header
          var xsrfValue = config.withCredentials || isURLSameOrigin(config.url) ?
          cookies.read(config.xsrfCookieName) :
          undefined;

          if (xsrfValue) {
            requestHeaders[config.xsrfHeaderName] = xsrfValue;
          }
        }

        // Add headers to the request
        if ('setRequestHeader' in request) {
          utils.forEach(requestHeaders, function setRequestHeader(val, key) {
            if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') {
              // Remove Content-Type if data is undefined
              delete requestHeaders[key];
            } else {
              // Otherwise add header to the request
              request.setRequestHeader(key, val);
            }
          });
        }

        if (requestData === undefined) {
          requestData = null;
        }

        // Send the request
        request.send(requestData);

        // Set the request timeout in MS
        request.waitForResponse(config.timeout);
        if (request.readyState !== 4) {
          request.abort();
          reject(createError('timeout of ' + config.timeout + 'ms exceeded', config, 'ECONNABORTED'));
          request = null;
        }
      } catch (err) {
        reject(createError(err.description, config, (err.number >>> 0).toString(16)));
        // Clean up request
        request = null;
      }
    });
  },
});

主に変更した点は以下になります。

  • new XMLHttpRequest();new ActiveXObject('MSXML2.ServerXMLHTTP');に変更
  • timeoutの設定をsetTimeoutsメソッドを使った方法に変更
  • XDomainRequestに関する処理を省いた
  • xhrのonerrorとontimeoutにメソッドを設定しないようにした
  • withCredentials、responseType、progressに関する設定をしないようにした
  • xhrのopenからsendまでをtry-catchでくくるようにした
  • catchした時にエラーメッセージとエラーコードを設定するようにした

JScriptで利用できるXHRは設定可能なプロパティが少ないため、その部分を削っています。
全体をtry-catchでくくっているのは、
本来、通信が失敗した場合はonerrorやontimeoutが呼ばれますが、JScriptではこれらを設定することができません。
JScriptではonerrorやontimeoutを呼ぶ代わりに例外を投げるので、try-catchでくくってあげています。

axiosを使った通信

先ほど生成したaxiosのインスタンスで通信を行う処理を書いてみます。

hoge.js
// 上のコードの続き
axios.defaults.baseURL = 'http://jsonplaceholder.typicode.com';

axios.get('/posts/1').then((res) => {
  WScript.Echo(res.data.title);
  WScript.quit();
})['catch']((err) => {
  if (err.code) {
    WScript.Echo(err.code);
  }
  WScript.Echo(err.message);
  WScript.quit();
});

for (;;) {
  WScript.Sleep(100);
}
C:\wsh>cscript hoge.js
Microsoft (R) Windows Script Host Version 5.7
Copyright (C) Microsoft Corporation 1996-2001. All rights reserved.

sunt aut facere repellat provident occaecati excepturi optio reprehenderit

注意点としては、リクエストを送ったあとには何か他の処理をしていないと、レスポンスが返ってくる前に終了してしまいます。
そのため、ここでは無限にsleepをして、リクエストが返ってきたらquitしてあげています。
また、Promiseのcatchは上のように書いてあげる必要があります。
IE9未満ではcatchが構文エラーになるようです。
transform-es3-member-expression-literalsを適用することで、今までながらの書き方をすることもできます。

おわりに

JScriptも頑張れば最近のライブラリを使いまくれるのでいいですね。
需要はアレですが、何かの参考になるとうれしいです。

参考

abcang
JavaScriptとかRubyとかがすきです
https://abcang.net
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした