axiosにカプセル化Vueの話
axios Vueのは、公式には、それを紹介する公式の導入axiosで、HTTPライブラリを推奨され、これは次のようになります。
Axiosは、HTTPライブラリの約束に基づいており、あなたは、ブラウザとのNode.jsを使用することができます。
良いHTTPライブラリとして、axiosはVUE-リソースが公式のチームのVueによって維持されてきた敗北、Vueが、特に小さな作者の権利を獲得し、強くVueのプロジェクトのHTTPライブラリのための最良の選択になることをお勧めします。
、axiosが良いHTTPライブラリですが、しかし、直接のプロジェクトで使用するのは簡単ではありませんので、我々はパッケージにある程度を設定する必要があり、コードの重複を減らす、簡単に呼び出し。ここでは、Vueのパッケージのaxiosで話をしなければなりません。
始めます
実際には、オンラインのロットコードaxiosパッケージに、それらのほとんどは、次のコードに似た設定ファイルのエントリ(main.js)、で定義されたグローバルオブジェクト属性axios形です。
axios.defaults.timeout = 10000
プログラムは、入口不便後メンテナンスに2つの欠点は、まず、コード連結Axiosパッケージファイルを有し、第二に、Axiosの方法を定義したグローバルオブジェクト属性を使用して構成され、コードがあまりにも断片化されています。
問題のために、私は大きなコアアイデアVueのソース構造を使用する-ファイルの分割などの機能を、簡単にメンテナンス以降。別の作成http.js
やhttp.ts
ファイルを、ファイルは、そのパッケージ構成でようやくプロトタイプをaxiosを導入し、Vueのに取り付けられています。このとき、各変更axios構成は、唯一の無関係な機能に影響を与えることができない、対応するファイルを変更する必要があります。
パッケージを設定するには、設定項目によってaxiosインスタンスを作成するために、公式の推薦axios使用して、質問2については。
コードは以下の通りであります:
// http.js
import axios from 'axios'
// 创建 axios 实例
const service = axios.create({
// 配置项
})
環境設定に従ってベースURL
URLは絶対アドレスでない限り、ベースURLアドレスプレフィックス要求属性は自動的に、フロントURLに追加されます。通常の状況下では、生産モードでの開発環境で異なるベースURLを持っているので、我々は、異なる環境に応じて、異なるベースURLに切り替える必要があります。
そこdevServer、固定アドレスプレフィックスURL書き換えに基づいて要求の必要性を持っているので、ので、開発モードでは、開発環境では、ベースURLは、次のような、固定値に設定します/apis
。
生産モードでは、異なる要求に応じたJavaモジュールが別のbaseURLを設けてもよいプレフィックス。
具体的なコードは次のよう:
// 根据 process.env.NODE_ENV 区分状态,切换不同的 baseURL
const service = axios.create({
baseURL: process.env.NODE_ENV === 'production' ? `/java` : '/apis',
})
リクエストヘッダの統一セット
ここでは、我々は質問を話し、パッケージは何ですか?私の意見では、パッケージは少ない呼び出し元のコードでシーンをより多くのコールを覆われています。
ほとんどの場合、要求ヘッダーが固定されている、ので、ほんの数例で、あなたはいくつかの特別なリクエストヘッダが必要になりますので、ここでは、私はプログラムは、基本構成として、ユニバーサルリクエストヘッダで使用しました。基本的な構成をカバーする特別な要求ヘッダー、パラメータとして特別な要求ヘッダーを、必要なとき。
コードは以下の通りであります:
const service = axios.create({
...
headers: {
get: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
// 在开发中,一般还需要单点登录或者其他功能的通用请求头,可以一并配置进来
},
post: {
'Content-Type': 'application/json;charset=utf-8'
// 在开发中,一般还需要单点登录或者其他功能的通用请求头,可以一并配置进来
}
},
})
クロスドメイン、タイムアウト、レスポンスコード処理
axiosがクロスドメインを許可するかどうかのプロパティ--withCredentialsを提供し、これらの二つの属性によって構成プロパティ--timeoutタイムアウト、あなたは簡単にクロスドメインおよびタイムアウトの問題を処理することができます。
以下に、我々はそれが応答コードの処理であると言います。
axiosは解決するか、約束を拒否された特定のHTTPレスポンスのステータスコードを定義するためにvalidateStatusプロパティを提供します。したがって、通常の設定で、我々は、ステータスコード304を要求する2に設定または直列状態を解決するため、残りの状態が拒否されます。その結果、我々はビジネスのコードで、統一された応答がキャッチ悪い要求、均一処理を使用して撮影しているということです。
私は非同期のawait内のコードを使用していますが、私たちは皆知っているので、トラブルをキャッチするのに最適な方法をキャプチャし、非同期を待つので、ここでは、私は、すべての応答が状態を解決するために設定され、その後、統一プロセスを選択しました。
このコードの一部を次のように
const service = axios.create({
// 跨域请求时是否需要使用凭证
withCredentials: true,
// 请求 30s 超时
timeout: 30000,
validateStatus: function () {
// 使用async-await,处理reject情况较为繁琐,所以全部返回resolve,在业务代码中处理异常
return true
},
})
要求、応答処理
各要求または受信、要求または応答に応じて、使用することなくAxiosをシリアル化する必要があります。
axiosでは、transformRequest
データの変更要求を送信する前に、サーバーへの許可の要求、transformResponse
そして/キャッチに転送する前に、応答データの変更ができます。
これらの2つのフックにより、我々は繰り返されるコードシーケンスを大幅に節約することができます。
コードは以下の通りであります:
const service = axios.create({
// 在向服务器发送请求前,序列化请求数据
transformRequest: [function (data) {
data = JSON.stringify(data)
return data
}],
// 在传递给 then/catch 前,修改响应数据
transformResponse: [function (data) {
if (typeof data === 'string' && data.startsWith('{')) {
data = JSON.parse(data)
}
return data
}]
})
迎撃機
ブロッカーは、リクエストとレスポンスのインターセプタインターセプタに、それらが処理される前に傍受やキャッチ要求または応答しています。
キャッチ非同期待つ難しい問題以来、前に述べたように、それはまた、エラーが解決ステータスとして扱われている場合です。しかしながら、これは要求に応じて、問題となるか、エラーの場合には、結果がデータ・プロトコルで定義されたMSGフィールド(メッセージ)ではありません。何かがうまくいかない場合は、手動で返されるデータの形式に合わせてリターンを生成するので、我々は必要です。
、ビジネスに、リクエストインターセプタに追加の処理要件を行うので、ステータス要求インタセプタを解決する必要がないので、ちょうどそれに直接戻りました。
リクエストインターセプタのコードは次のとおりです。
// 请求拦截器
service.interceptors.request.use((config) => {
return config
}, (error) => {
// 错误抛到业务代码
error.data = {}
error.data.msg = '服务器异常,请联系管理员!'
return Promise.resolve(error)
})
つまり、ステータスコードが2または304シリーズではありません、要求または応答エラーに加えて、状況はプロトコル仕様を満たしていないメッセージの本文の復帰につながるがあり、前のトーク応答インターセプター、またはその問題を、是非。この時点で、我々はまだ、同じプロセスを行う必要があります - 手動で返されるデータの形式に沿ったリターンを生成します。しかし、一つのことは同じではありません、我々はまた、処理ラインの後に問題を容易にするために、ステータスコードに応じて異なるメッセージを生成する必要があります。
インターセプタの応答コードは次のとおりです。
// 根据不同的状态码,生成不同的提示信息
const showStatus = (status) => {
let message = ''
// 这一坨代码可以使用策略模式进行优化
switch (status) {
case 400:
message = '请求错误(400)'
break
case 401:
message = '未授权,请重新登录(401)'
break
case 403:
message = '拒绝访问(403)'
break
case 404:
message = '请求出错(404)'
break
case 408:
message = '请求超时(408)'
break
case 500:
message = '服务器错误(500)'
break
case 501:
message = '服务未实现(501)'
break
case 502:
message = '网络错误(502)'
break
case 503:
message = '服务不可用(503)'
break
case 504:
message = '网络超时(504)'
break
case 505:
message = 'HTTP版本不受支持(505)'
break
default:
message = `连接出错(${status})!`
}
return `${message},请检查网络或联系管理员!`
}
// 响应拦截器
service.interceptors.response.use((response) => {
const status = response.status
let msg = ''
if (status < 200 || status >= 300) {
// 处理http错误,抛到业务代码
msg = showStatus(status)
if (typeof response.data === 'string') {
response.data = { msg }
} else {
response.data.msg = msg
}
}
return response
}, (error) => {
// 错误抛到业务代码
error.data = {}
error.data.msg = '请求超时或服务器异常,请检查网络或联系管理员!'
return Promise.resolve(error)
})
ヒント:ヒントは、スイッチケースのコードの塊の上に、あなたが最適化するための戦略パターンを使用することができます〜
サポート活字体
いくつかの時間前から、私は、ファイルのTSを上書きするために、すべてのJSファイルを自分の強迫性障害を満たすために、部門内活字体を押しました。axios自体活字体関連のサポートなので、これだけ対応するタイプをインポートする必要があり、その後に割り当てられます。
完全なコード
// http.ts
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'
const showStatus = (status: number) => {
let message = ''
switch (status) {
case 400:
message = '请求错误(400)'
break
case 401:
message = '未授权,请重新登录(401)'
break
case 403:
message = '拒绝访问(403)'
break
case 404:
message = '请求出错(404)'
break
case 408:
message = '请求超时(408)'
break
case 500:
message = '服务器错误(500)'
break
case 501:
message = '服务未实现(501)'
break
case 502:
message = '网络错误(502)'
break
case 503:
message = '服务不可用(503)'
break
case 504:
message = '网络超时(504)'
break
case 505:
message = 'HTTP版本不受支持(505)'
break
default:
message = `连接出错(${status})!`
}
return `${message},请检查网络或联系管理员!`
}
const service = axios.create({
// 联调
baseURL: process.env.NODE_ENV === 'production' ? `/` : '/apis',
headers: {
get: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'
},
post: {
'Content-Type': 'application/json;charset=utf-8'
}
},
// 是否跨站点访问控制请求
withCredentials: true,
timeout: 30000,
transformRequest: [(data) => {
data = JSON.stringify(data)
return data
}],
validateStatus () {
// 使用async-await,处理reject情况较为繁琐,所以全部返回resolve,在业务代码中处理异常
return true
},
transformResponse: [(data) => {
if (typeof data === 'string' && data.startsWith('{')) {
data = JSON.parse(data)
}
return data
}]
})
// 请求拦截器
service.interceptors.request.use((config: AxiosRequestConfig) => {
return config
}, (error) => {
// 错误抛到业务代码
error.data = {}
error.data.msg = '服务器异常,请联系管理员!'
return Promise.resolve(error)
})
// 响应拦截器
service.interceptors.response.use((response: AxiosResponse) => {
const status = response.status
let msg = ''
if (status < 200 || status >= 300) {
// 处理http错误,抛到业务代码
msg = showStatus(status)
if (typeof response.data === 'string') {
response.data = {msg}
} else {
response.data.msg = msg
}
}
return response
}, (error) => {
// 错误抛到业务代码
error.data = {}
error.data.msg = '请求超时或服务器异常,请检查网络或联系管理员!'
return Promise.resolve(error)
})
export default service