【Vue.js】axiosについてまとめます(CORS、パラメーター)

Web

Webサービスについて

Vue.jsなどで開発するWebアプリケーションの多くは、外部のまたは自社(自身)で作成したWebサービスを通じてリソースを取得したり、更新したりします。

Webサービスについて簡単に説明しておくと、対システム向けのシステムのことです。少しわかりにくいかもしれませんが、Webサービスは他のシステムからのリクエストを受け取り、その内容に応じた処理を行い、結果を返します。

Webサービスには、SOAPベース、RESTベースなど異なるモデルがありますが、設計が他よりも単純なRESTベースのものが多いです。

REST

RESTはREpresentational State Transferの略で、先ほど説明したようにWebサービスのモデルの1つです。今回の本題である外部リソースの操作も、RESTベースのWebサービスから行うことを想定しています。

ではRESTについて必要最低限のことだけ説明しておきます。

データについて

RESTによって返されるデータ形式は、XMLかjsonがほとんどです。この記事では、jsonを想定して解説をしていきます。

HTTPメソッド

RESTでは次のようにリソースの操作とHTTPメソッドに関連性をもたせます。

操作HTTPメソッド
登録(Create)POST
取得(Read)GET
更新(Update)PUT
削除(Delete)DELETE

HTTPステータスコード

RESTではHTTPステータスコードによって、処理の結果を返します。しっかりと意味の合うコードを返すように設計する必要があります。ステータスコードについては、以下のWikiを参考にしてください。

HTTPステータスコード - Wikipedia

Go言語によるサンプル

今回はGo言語により簡易的なWebサービスを作り、axiosでここにアクセスしたいと思います。特にGo言語である必要はありませんが、個人的にこれが1番楽というだけです。

package main

import (
  "encoding/json"
  "net/http"
)

type Status struct {
  Status  string `json:"status"`
  Message string `json:"message"`
}

func main() {
  server := http.Server{
    Addr: "127.0.0.1:8082",
  }
  http.HandleFunc("/api", handler)
  server.ListenAndServe()
}

func handler(w http.ResponseWriter, r *http.Request) {
  var status Status
  switch r.Method {
  case "GET":
    status = Status{Status: "ok", Message: "GET METHOD"}
  case "POST":
    status = Status{Status: "ok", Message: "POST METHOD"}
  case "PUT":
    status = Status{Status: "ok", Message: "PUT METHOD"}
  case "DELETE":
    status = Status{Status: "ok", Message: "DELETE METHOD"}
  default:
    status = Status{Status: "error", Message: "Not defined"}
  }
  w.Header().Set("Content-Type", "application/json")
  output, _ := json.MarshalIndent(&status, "", "\t\t")
  w.Write(output)
}

簡単に解説をしておくと、localhost:8082/api にアクセスすることでWebサービスが実行されます。実行結果としてjsonを返しますが、HTTPメソッドによってその内容が異なります。例えばGETでアクセスした場合は次のようなjsonが取得できます。

{
    "status": "OK",
    "message": "GET METHOD"
}

Webサービスへのアクセス方法

WebアプリケーションからWebサービスにアクセスするには、Ajax(Asynchronous Javascript + XML)を使用します。Ajaxは、非同期通信によりWebサービスにアクセスします。

Ajaxの方法もいくつかあり、よく見かけるのは jQueryのajax() のような気がします。が、Vue.jsで推奨されているのはaxiosというものです。

axiosの導入

今回はVue CLIを想定して話を進めていきます。まずaxiosをインストールします。

$ npm install axios
$ yarn add axios

axiosに限った話ではないのですが、インストールしたライブラリを読み込むには2つの方法があります。

1つは次のように使用したいファイル(.vue)で直接 import する方法です。

import axios from 'axios'

これだと読み込んだファイルでのみ有効になるため、必要なファイルごとに読み込む必要があります。

そこでもう1つの方法として、インスタンスプロパティとして定義する方法があります。インスタンスプロパティは、いろいろなコンポーネントで使いたいデータやインターフェースを、Vueインスタンスのプロパティとして登録することで、どのコンポーネントからもアクセスできるようにすることです。Vueインスタンスを定義しているmain.jsを次のように変更します。

import Vue from 'vue'
import App from './App.vue'
import axios from 'axios'    //←これを追加

Vue.config.productionTip = false
Vue.prototype.$axios = axios    //←これを追加

new Vue({
  render: function (h) { return h(App) },
}).$mount('#app')

各コンポーネントからインスタンスプロパティにアクセスする方法は次のようになります。

this.$axios

axiosの基本的な使い方

では試しに先程作成したWebサービスに対して、axiosを使ってGETメソッドでアクセスしてみます。axiosにはHTTPメソッドごとにメソッドが用意されています。GETメソッドでアクセスする場合にはget()を使用します。

methods: {
  get() {
    this.$axios.get("http://localhost:8082/api").then(res => {
      console.log(res)
    }).catch(err => {
      console.log(err)
    })
  }
}

成功すればコンソールに次のような結果が表示されます。

{
  data: {status: "ok", message: "GET METHOD"}
  status: 200
  //その他は省略…
}

見てわかるように、statusにはHTTPステータスが、dataにはWebサービスから取得したjson形式のデータが設定されています。

さて、ここで気になるのが thencatchだと思います。thenには、Webサービスからレスポンスが返ってきた後の処理を定義します。引数の res は、上記で表示したようにレスポンスの内容になります。catchには、HTTPステータスコードがエラーの場合の処理を記述します。引数の err は、エラーの内容になります。

ここで1つ思い出してほしいのは、Ajaxは非同期にWebサービスにアクセスしていることです。例えば次のようにした場合、コンソールはどのように表示されるでしょうか。

this.$axios.get("url").then(res => {
    console.log("1");
});
console.log("2");

答えは、「2」、「1」の順番で表示されます。しつこいようですが、Ajaxは非同期で通信されるため、axios以降に定義されている処理はレスポンスを待たずして実行されます。レスポンス後の処理はあくまで then で定義された処理だけなのです。

その他のPOST、PUT、DELETEもメソッドがそれぞれpost()、put()、delete()になるだけで、基本的な使用方法はget()と変わりありません。

CORS (Cross-Origin Resource Sharing)

実はこのままではWebサービスからデータを取得することはできません。コンソールを確認すると、次のようなエラーメッセージが表示されているはずです。

Access to XMLHttpRequest at ‘http://localhost:8082/api’ from origin ‘http://localhost:8080’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

エラーメッセージにblocked by CORS policyとあるように、CORSによってブロックされているというエラーです。

CORSとは何かという話ですが、一言でいうと別のオリジンからのリソースを制限するための仕組みです。と言われてもいまいちわからないと思います。

まずオリジンについて説明します。オリジンはプロトコル・ホスト・ポート番号のセットのことで、すべてが同じであれば同一オリジン、1つでも違う場合は別のオリジンとなります。今回の場合、Webサービスのオリジンは「http://localhost:8082」、Webアプリケーションのオリジンは「http://localhost:8080」とポート番号が違うため別のオリジンとなります。

次にCORSの対象となるリクエストについて説明します。すべてのリクエストがCORSによりブロックされるわけではなく、特定のリクエストでのみブロックされます。今回扱っているAjaxは、XMLHttpRequestという仕組みを使っており、これがCORSの対象となっています。

他にも細かい話はあるのですが、ここではこれくらいにしておきます。

では、どのようにしてこのエラーを解決すればいいのでしょうか。

1つはWebサービス側で特定のWebアプリケーションからのアクセスを許可する方法です。次のようにWebサービスのレスポンスにヘッダー情報を追加します。

w.Header().Set("Access-Control-Allow-Origin", "http://localhost:8080")
w.Header().Set("Access-Control-Allow-Methods", "POST,GET,PUT,DELETE")

Access-Control-Allow-Originには、リクエストを許可するオリジンを設定します。すべてのリクエストを許可する場合はアスタリスク(*)を設定します。

Access-Control-Allow-Methodsには、リクエストできるHTTPメソッドを設定します。デフォルトだとPOST、GETは利用できるのですが、PUT、DELETEは利用できないため追加する必要があります。

CORSに関するヘッダー情報は他にもあるのですが、とりあえずこれでリクエストできるようになると思います。

ただ、自作したWebサービスならこのように変更可能ですが、他社(他者)が作ったWebサービスだとそうはいきません。

そこでもう1つの解決方法として、プロキシを使用します。その前にVue CLI の config について少し説明します。

Vue CLIでは、ルートディレクトリに vue.config.js というファイルを作れば、それを config ファイルとして自動で判断してくれます。config については割愛しますが、以下にドキュメントをリンクしておきます。

Configuration Reference | Vue CLI
🛠️ Standard Tooling for Vue.js Development

では、vue.config.js を次のように設定してください。

module.exports = {
  devServer: {
    proxy: 'http://localhost:8082'
  }
};

そして、Webサービスにリクエストするときは次のようにURLを指定します。

this.$axios.get('/api').then(res => {

});

細かい解説は割愛しますが、こうすることであたかも同一オリジンからリクエストをしたようにすることができます。

パラメータの設定

パラメータについてはWebサービス側の実装の問題もあるため、一概にこれとは言えませんが大体は次のケースでいけます。

クエリパラメータ

GETの場合だと、単純に「http://localhost:8082/api?param1=value1」のようにクエリパラメータを設定すればいいです。

paramsオプション

次のように、第2引数にparamsを設定します。これはクエリパラメータの別の指定方法なのでGETで使用する方法です。

const params = {
  "param1": "value1",
  "param2": "value2"
};
this.$axios.get("url", {params: params}).then(res => {

});

URLSearchParams

POSTなどapplication/x-www-form-urlencoded形式でリクエストする場合は、URLSearchParamsを使用します。

let params = new URLSearchParams();
params.append("param1", "value1");
params.append("param2", "value2");

this.$axios.post("url", params).then(res => {

});

仮にIEでURLSearchParamsを使用する場合は、次をインストールしてください。

url-search-params-polyfill
a simple polyfill for javascript URLSearchParams

 

- Vue.jsのおすすめ書籍はコチラ -

コメント

タイトルとURLをコピーしました