request-axios.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. import axios from 'axios'
  2. import { Message, MessageBox } from 'element-ui'
  3. import router from '@/router'
  4. /**
  5. * 配置的优先顺序
  6. * 查找顺序:lib/defaults.js 中库的默认值 -----> 实例的 defaults 属性 -----> 请求的 config 参数
  7. * 优先级为查找的反序,如上顺序中,后面覆盖前面
  8. * 优先级:请求的 config 参数 -----> 实例的 defaults 属性 -----> lib/defaults.js 中库的默认值
  9. *
  10. * @type {AxiosInstance}
  11. */
  12. /**
  13. * 响应消息体
  14. * {
  15. * // `data` 由服务器提供的响应
  16. * data: {},
  17. * // `status` 来自服务器响应的 HTTP 状态码
  18. * status: 200,
  19. * // `statusText` 来自服务器响应的 HTTP 状态信息
  20. * statusText: 'OK',
  21. * // `headers` 服务器响应的头
  22. * headers: {},
  23. * // `config` 是为请求提供的配置信息
  24. * config: {},
  25. * // `request` 生成响应的请求
  26. * // It is the last ClientRequest instance in node.js (in redirects)
  27. * // and an XMLHttpRequest instance the browser
  28. * request: {}
  29. * }
  30. *
  31. */
  32. /**
  33. * Axios封装
  34. */
  35. class AxiosService {
  36. /**
  37. * 定义公共属性
  38. * @returns
  39. */
  40. buildOptions() {
  41. return {
  42. // ---------- 自定义配置 ----------
  43. // HTTP response消息体 {data: {}, status: 200, statusText: 'OK', headers: {}, config: {}, request: {}}
  44. // 服务端消息体 service body {code: '0', message: 'success', data: {page: 0, totalPage: 1, count: 0, totalCount: 0, rows: [{},{}]}
  45. // HTTP response消息体中response.data即是服务端消息体service body
  46. // service body中的data是服务端消息体中的业务数据 data
  47. // 解构分为,解构HTTP response消息体, 和解构服务端消息体service body(即解构response.data)
  48. // never, 不解构HTTP response消息体
  49. // serviceBody 和 serviceData, 一定会解构出HTTP response消息体中的data
  50. // 默认serviceBody, 解构HTTP response, 但不解构服务端消息体service body, 返回服务端消息体service body全部
  51. // serviceData, 解构HTTP response, 并解构出服务端消息体service body中的业务数据data
  52. // 配置值为 never | serviceBody(默认) | serviceData
  53. deconstruction: 'serviceBody',
  54. // ---------- 以下为原生配置 ----------
  55. // `url` 是用于请求的服务器 URL
  56. url: '',
  57. // `method` 是创建请求时使用的方法
  58. method: 'get', // 默认是 get
  59. // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
  60. // 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
  61. // url = base url + request url, 区分开发环境和生产环境
  62. baseURL: '/api',
  63. // `headers` 是即将被发送的自定义请求头
  64. headers: { 'X-Requested-With': 'Songmao' },
  65. // `params` 是即将与请求一起发送的 URL 参数
  66. // 必须是一个无格式对象(plain object)或 URLSearchParams 对象
  67. params: {
  68. // xxx: yyy
  69. },
  70. // `data` 是作为请求主体被发送的数据
  71. // 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
  72. // 在没有设置 `transformRequest` 时,必须是以下类型之一:
  73. // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  74. // - 浏览器专属:FormData, File, Blob
  75. // - Node 专属: Stream
  76. data: {
  77. // xxx: yyy
  78. },
  79. // `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
  80. // 如果请求话费了超过 `timeout` 的时间,请求将被中断
  81. timeout: 10000,
  82. // `withCredentials` 表示跨域请求时是否需要使用凭证,// 默认的false
  83. withCredentials: true,
  84. // `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
  85. responseType: 'json', // 默认的
  86. // `onUploadProgress` 允许为上传处理进度事件
  87. onUploadProgress: function(progressEvent) {
  88. // 对原生进度事件的处理
  89. },
  90. // `onDownloadProgress` 允许为下载处理进度事件
  91. onDownloadProgress: function(progressEvent) {
  92. // 对原生进度事件的处理
  93. },
  94. // `maxContentLength` 定义允许的响应内容的最大尺寸
  95. maxContentLength: 2000,
  96. // `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
  97. validateStatus: function(status) {
  98. return status >= 200 && status < 300 // 默认的
  99. },
  100. // 'proxy' 定义代理服务器的主机名称和端口
  101. // `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
  102. // 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。
  103. proxy: {
  104. // // e.g.
  105. // host: '127.0.0.1',
  106. // port: 8080
  107. // auth: : {
  108. // username: 'xxx',
  109. // password: 'yyy'
  110. // }
  111. }
  112. }
  113. }
  114. /**
  115. * 实例化 Axios
  116. */
  117. constructor() {
  118. // 实例化axios对象
  119. this.inst = axios.create(this.buildOptions())
  120. /**
  121. * request interceptor
  122. */
  123. this.inst.interceptors.request.use(
  124. config => {
  125. // do something before request is sent
  126. if (!config.deconstruction) {
  127. const xConfig = {
  128. // 默认从response中解构出服务端消息体
  129. deconstruction: 'serviceBody'
  130. }
  131. config = Object.assign({}, config, xConfig)
  132. }
  133. return config
  134. },
  135. error => {
  136. // do something with request error
  137. return Promise.reject(error)
  138. }
  139. )
  140. /**
  141. * response interceptor
  142. */
  143. this.inst.interceptors.response.use(
  144. response => {
  145. const { data, status, statusText, config } = response
  146. const deconstruction = config.deconstruction || 'serviceBody'
  147. // ---------- 返回response 消息体 ----------
  148. if (deconstruction === 'never') {
  149. return response => response
  150. }
  151. // ---------- 返回服务端消息体 ----------
  152. if (deconstruction === 'serviceBody') {
  153. if (status === 200) {
  154. return data
  155. } else {
  156. Message({
  157. type: 'error',
  158. title: '消息',
  159. message: statusText || 'Http Error',
  160. duration: 5 * 1000
  161. })
  162. return Promise.reject(new Error(statusText || 'Http Error'))
  163. }
  164. }
  165. // ---------- 返回服务端消息体中的data ----------
  166. if (!data) {
  167. Message({
  168. type: 'error',
  169. title: '消息',
  170. message: 'Error: HTTP消息体data为空',
  171. duration: 5 * 1000
  172. })
  173. return Promise.reject(new Error('Error: HTTP消息体data为空'))
  174. }
  175. const res = data
  176. if (!res.code) {
  177. Message({
  178. type: 'error',
  179. title: '消息',
  180. message: 'Error: 服务端未返回code',
  181. duration: 5 * 1000
  182. })
  183. return Promise.reject(new Error('Error: 服务端未返回code'))
  184. }
  185. if (res.code !== '0') {
  186. Message({
  187. type: 'error',
  188. title: '消息',
  189. message: res.message ? '【' + res.code + ':' + res.message + '】' : '业务异常',
  190. duration: 5 * 1000
  191. })
  192. // ---------- 服务端需要处理的消息码 ----------
  193. // 服务端自定义消息码处理
  194. // 100012: Illegal token, 100020: SESSION_EXPIRE
  195. if (res.code === '100012' || res.code === '100020') {
  196. MessageBox.confirm(res.message ? '【' + res.code + ':' + res.message + '】, 非法请求, 或会话过期' : '非法请求, 或会话过期', '警告', {
  197. type: 'warning',
  198. confirmButtonText: '确认',
  199. cancelButtonText: '取消'
  200. }).then(() => {
  201. router.push({ path: '/login' })
  202. })
  203. }
  204. // others server message code......
  205. return Promise.reject(new Error(res.message || '业务异常'))
  206. } else {
  207. // 返回服务端消息体Service Body 中的 data
  208. return res.data
  209. }
  210. },
  211. error => {
  212. Message({
  213. type: 'error',
  214. message: error.message,
  215. duration: 5 * 1000
  216. })
  217. return Promise.reject(error)
  218. }
  219. )
  220. }
  221. // ---------- 对外提供访问方法 ----------
  222. instance() {
  223. return this.inst
  224. }
  225. setOptions(options) {
  226. this.inst.defaults = Object.assign({}, this.inst.defaults, options)
  227. }
  228. request(options) {
  229. return this.inst.request(options)
  230. }
  231. get(url, options) {
  232. return this.inst.get(url, options)
  233. }
  234. post(url, options) {
  235. return this.inst.post(url, options)
  236. }
  237. }
  238. const Service = (() => new AxiosService())()
  239. export default Service