>웹 프론트엔드 >View.js >vue에서 axios의 캡슐화 요청을 구문 분석합니다(단계 코드 사용).

vue에서 axios의 캡슐화 요청을 구문 분석합니다(단계 코드 사용).

藏色散人
藏色散人앞으로
2022-08-10 10:05:541800검색

1. 소개

axios는 XMLHttpRequest 서비스를 기반으로 HTTP 요청을 수행하고, Promise를 지원하며, 브라우저 측과 Node.js 측을 지원합니다. Vue2.0부터 Youda는 vue-resource의 공식 추천을 취소하고 대신 axios를 추천하겠다고 발표했습니다. 이제 Axios는 대부분의 Vue 개발자에게 첫 번째 선택이 되었습니다. (Axios에 익숙하지 않은 경우 여기에서 해당 API를 확인할 수 있습니다.) [관련 권장사항: vue.js 영상 튜토리얼XMLHttpRequest 服务来执行 HTTP 请求,支持丰富的配置,支持 Promise,支持浏览器端和 Node.js 端。自Vue2.0起,尤大大宣布取消对vue-resource 的官方推荐,转而推荐 axios。现在 axios 已经成为大部分 Vue 开发者的首选。( 如果你还不熟悉 axios,可以在这里查看它的API。)【相关推荐:vue.js视频教程

封装前,先来看下,不封装的情况下,一个实际项目中axios请求的样子。

大概是长这样:

axios('http://localhost:3000/data', {
  method: 'GET',
  timeout: 1000,
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json',
    Authorization: 'xxx',
  },
  transformRequest: [function (data, headers) {
    return data;
  }],
  // 其他请求配置...
})
.then((data) => {
  // todo: 真正业务逻辑代码
  console.log(data);
}, (err) => {
  if (err.response.status === 401) {
  // handle authorization error
  }
  if (err.response.status === 403) {
  // handle server forbidden error
  }
  // 其他错误处理.....
  console.log(err);
});

可以看到在这段代码中,页面代码逻辑只在第15行处,上方的一大块请求配置代码和下方一大块响应错误处理代码,几乎跟页面功能没有关系,而且每个请求中这些内容都差不多,甚至有的部分完全一样。

二、封装后

1.封装步骤

封装的本质就是在待封装的内容外面添加各种东西,然后把它们作为一个新的整体呈现给使用者,以达到扩展和易用的目的。

封装 axios 要做的事情,就是把所有HTTP请求共用的配置,事先都在axios上配置好,预留好必要的参数和接口,然后把它作为新的axios返回。

目录结构如下(由Vue-cli 3.0 生成):

|--public/
|--mock/
|   |--db.json  # 我新建的接口模拟数据
|--src/
|   |--assets/
|   |--components/
|   |--router/
|   |--store/
|   |--views/
|       |--Home.Vue
|   |--App.vue
|   |--main.js
|   |--theme.styl
|--package.json
|...

2.封装目标

在 Home 页,发起 axios 请求时就像调用一个只有少量参数的方法一样简单,这样我就可以专注业务代码了。

1. 将 axios 封装到一个独立的文件

  • 在src下创建 utils/http.js 文件
  cd src
  mkdir utils
  touch http.js
  • 引入 axios
  // src/utils/http.js
  import axios from 'axios';
  • 创建一个类
  //src/utils/http.js
  //...
  class NewAxios {
  
  }
  • 给不同环境配置不同请求地址

根据process.env.NODE_ENV 配置不同的 baseURL,使项目只需执行相应打包命令,就可以在不同环境中自动切换请求主机地址。

// src/utils/http.js

//...
const getBaseUrl = (env) => {
  let base = {
    production: '/',
    development: 'http://localhost:3000',
    test: 'http://localhost:3001',
  }[env];
  if (!base) {
    base = '/';
  }
  return base;
};

class NewAxios {
  constructor() {
    this.baseURL = getBaseUrl(process.env.NODE_ENV);
  }
}
  • 配置超时时间

timeout属性,我一般设置10秒。

// src/utils/http.js

//...
class NewAxios {
  constructor() {
    //...
    this.timeout = 10000;
  }
}
  • 配置允许携带凭证

widthCredentials属性设为true

// src/utils/http.js

//...
class NewAxios {
  constructor() {
    //...
    this.withCredentials = true;
  }
}
  • 给这个类创建实例上的方法request

request 方法里,创建新的axios实例,接收请求配置参数,处理参数,添加配置,返回axios实例的请求结果(一个promise对象)。

你也可以不创建,直接使用默认导出的axios实例,然后把所有配置都放到它上面,不过这样一来整个项目就会共用一个axios实例。虽然大部分项目下这样够用没问题,但是有的项目中不同服务地址的请求和响应结构可能完全不同,这个时候共用一个实例就没办法支持了。所以为了封装可以更通用,更具灵活性,我会使用axioscreate方法,使每次发请求都是新的axios实例。

// src/utils/http.js

//...
class NewAxios {
  //...
  request(options) {
    // 每次请求都会创建新的axios实例。
    const instance = axios.create();
    const config = { // 将用户传过来的参数与公共配置合并。
      ...options,
      baseURL: this.baseURL,
      timeout: this.timeout,
      withCredentials: this.withCredentials,
    };
    // 配置拦截器,支持根据不同url配置不同的拦截器。
    this.setInterceptors(instance, options.url);
    return instance(config); // 返回axios实例的执行结果
  }
}

因为拦截器配置内容比较多,所以封装成一个内部函数了。

  • 配置请求拦截器

在发送请求前对请求参数做的所有修改都在这里统一配置。比如统一添加token凭证、统一设置语言、统一设置内容类型、指定数据格式等等。做完后记得返回这个配置,否则整个请求不会进行。

我这里就配置一个token

// src/utils/http.js

//...
class NewAxios {
  //...
  // 这里的url可供你针对需要特殊处理的接口路径设置不同拦截器。
  setInterceptors = (instance, url) => { 
    instance.interceptors.request.use((config) => { // 请求拦截器
      // 配置token
      config.headers.AuthorizationToken = localStorage.getItem('AuthorizationToken') || '';
      return config;
    }, err => Promise.reject(err));
  }
  //...
}
  • 配置响应拦截器

在请求的thencatch处理前对响应数据进行一轮预先处理。比如过滤响应数据,更多的,是在这里对各种响应错误码进行统一错误处理,还有断网处理等等。

我这里就判断一下403和断网。

// src/utils/http.js

//...
class NewAxios {
  //...
  setInterceptors = (instance, url) => {
    //...
    instance.interceptors.response.use((response) => { // 响应拦截器
      // todo: 想根据业务需要,对响应结果预先处理的,都放在这里
      console.log();
      return response;
    }, (err) => {
      if (err.response) { // 响应错误码处理
        switch (err.response.status) {
          case '403':
            // todo: handler server forbidden error
            break;
            // todo: handler other status code
          default:
            break;
        }
        return Promise.reject(err.response);
      }
      if (!window.navigator.online) { // 断网处理
        // todo: jump to offline page
        return -1;
      }
      return Promise.reject(err);
    });
  }
  //...
}

另外,在拦截器里,还适合放置loading等缓冲效果:在请求拦截器里显示loading,在响应拦截器里移除loading。这样所有请求就都有了一个统一的loading效果。

  • 默认导出新的实例
  // src/utils/http.js
  
  //...
  export default new NewAxios();

最后完整的代码如下:

// src/utils/http.js

import axios from 'axios';

const getBaseUrl = (env) => {
  let base = {
    production: '/',
    development: 'http://localhost:3000',
    test: 'http://localhost:3001',
  }[env];
  if (!base) {
    base = '/';
  }
  return base;
};

class NewAxios {
  constructor() {
    this.baseURL = getBaseUrl(process.env.NODE_ENV);
    this.timeout = 10000;
    this.withCredentials = true;
  }

  // 这里的url可供你针对需要特殊处理的接口路径设置不同拦截器。
  setInterceptors = (instance, url) => {
    instance.interceptors.request.use((config) => {
      // 在这里添加loading
      // 配置token
      config.headers.AuthorizationToken = localStorage.getItem('AuthorizationToken') || '';
      return config;
    }, err => Promise.reject(err));

    instance.interceptors.response.use((response) => {
      // 在这里移除loading
      // todo: 想根据业务需要,对响应结果预先处理的,都放在这里
      return response;
    }, (err) => {
      if (err.response) { // 响应错误码处理
        switch (err.response.status) {
          case '403':
            // todo: handler server forbidden error
            break;
            // todo: handler other status code
          default:
            break;
        }
        return Promise.reject(err.response);
      }
      if (!window.navigator.online) { // 断网处理
        // todo: jump to offline page
        return -1;
      }
      return Promise.reject(err);
    });
  }

  request(options) {
    // 每次请求都会创建新的axios实例。
    const instance = axios.create();
    const config = { // 将用户传过来的参数与公共配置合并。
      ...options,
      baseURL: this.baseURL,
      timeout: this.timeout,
      withCredentials: this.withCredentials,
    };
    // 配置拦截器,支持根据不同url配置不同的拦截器。
    this.setInterceptors(instance, options.url);
    return instance(config); // 返回axios实例的执行结果
  }
}

export default new NewAxios();

现在 axios

캡슐화에 앞서, 캡슐화가 없는 실제 프로젝트에서 Axios 요청이 어떤 모습인지 살펴보겠습니다.

아마 다음과 같을 것입니다:

🎜
// src/api/home.js 

import axios from '@/utils/http';
export const fetchData = options => axios.request({
  ...options,
  url: '/data',
});
export default {};
🎜이 코드에서 페이지 코드 로직은 15행에만 있고 상단에는 요청 구성 코드의 큰 블록이 있고 응답 오류 처리의 큰 블록이 있는 것을 볼 수 있습니다. 하단의 코드는 거의 페이지 기능과 관련이 없으며 요청마다 내용이 비슷하고 어떤 부분은 완전히 동일하기도 합니다. 🎜🎜2. 캡슐화 후🎜🎜🎜1. 캡슐화 단계🎜🎜🎜캡슐화의 본질은 캡슐화할 콘텐츠 외부에 다양한 것을 추가한 후 사용자에게 새로운 전체로 제시하여 확장성과 사용 편의성을 구현하는 것입니다. . 목적. 🎜🎜캡슐화 axios가 해야 할 일은 axios의 모든 HTTP 요청에 공통적인 구성을 미리 구성하고 필요한 매개변수와 인터페이스를 예약한 다음 이를 새로운 axios로 반환하는 것입니다. 🎜🎜🎜디렉토리 구조는 다음과 같습니다(Vue-cli 3.0에서 생성됨): 🎜🎜
🎜|--public/🎜|--mock/🎜| |--db.json # 내 새 인터페이스 시뮬레이션 데이터 🎜 |--src/🎜| |--컴포넌트/🎜| |--store/🎜| |--Home.Vue🎜| |- -App.vue🎜| |--main.js🎜|--theme.styl🎜|--package.json🎜|...🎜
🎜🎜2. 홈 페이지에서 axios 요청을 수행하는 것은 몇 가지 매개변수만으로 메소드를 호출하는 것만큼 간단하므로 비즈니스 코드에 집중할 수 있습니다. 🎜🎜🎜1. axios를 별도의 파일로 캡슐화🎜🎜
  • src 아래에 utils/http.js 파일 만들기
 // src/api/index.js
  
  export * from './home';
  • axios 소개
  • li>
// src/views/Home.vue

<template>
  <div class="home">
    <h1>This is home page</h1>
  </div>
</template>

<script>
// @ is an alias to /src
import { fetchData } from &#39;@/api/index&#39;;

export default {
  name: &#39;home&#39;,
  mounted() {
    fetchData()  // axios请求在这里
      .then((data) => {
        console.log(data);
      })
      .catch((err) => {
        console.log(err);
      });
  },
};
</script>
  • 클래스 만들기
rrreee
  • 다른 환경에 대해 다른 요청 주소 구성
🎜에 따르면 process.env.NODE_ENV 해당 패키징 명령을 실행하기만 하면 프로젝트가 다른 환경에서 요청 호스트 주소를 자동으로 전환할 수 있도록 다른 baseURL을 구성합니다. 🎜rrreee
  • 시간 제한
🎜timeout 속성을 ​​구성합니다. 저는 보통 10초로 설정합니다. 🎜rrreee
  • 자격 증명 전달을 허용하도록 구성
🎜widthCredentials 속성이 true🎜rrreee
  • 로 설정되었습니다. 클래스 생성 인스턴스에 대한 메서드 요청
🎜 request 메서드에서 새 axios 인스턴스를 생성하고 요청 구성 매개변수를 수신하고 매개변수를 처리하고 구성을 추가합니다. axios 인스턴스 결과(Promise 객체)에 대한 요청을 반환합니다. 🎜🎜기본으로 내보낸 axios 인스턴스를 생성하지 않고 직접 사용한 다음 모든 구성을 넣을 수도 있지만 이렇게 하면 전체 프로젝트가 하나의 axios 인스턴스를 공유하게 됩니다. 대부분의 프로젝트에서는 이것으로 충분하지만, 일부 프로젝트에서는 서로 다른 서비스 주소의 요청 및 응답 구조가 완전히 다를 수 있습니다. 이 경우 하나의 인스턴스를 공유하면 이를 지원할 수 없습니다. 따라서 캡슐화를 더욱 다양하고 유연하게 만들기 위해 axioscreate 메서드를 사용하여 각 요청이 새로운 axios 인스턴스가 되도록 하겠습니다. 🎜rrreee🎜인셉터 구성 내용이 상대적으로 크기 때문에 내부 기능으로 캡슐화됩니다. 🎜
  • 요청 인터셉터 구성
🎜요청을 보내기 전 요청 매개변수에 대한 모든 수정 사항이 여기에서 구성됩니다. 예를 들어 토큰 자격 증명을 균일하게 추가하고, 언어를 균일하게 설정하고, 콘텐츠 유형을 균일하게 설정하고, 데이터 형식을 지정하는 등의 작업을 수행합니다. 완료 후에는 이 구성을 반환해야 합니다. 그렇지 않으면 전체 요청이 진행되지 않습니다. 🎜🎜여기서 토큰을 구성하겠습니다. 🎜rrreee
  • 응답 인터셉터 구성
🎜요청의 then 또는 catch 전에 응답 데이터 사전 처리 라운드를 수행합니다. 코드> 처리 거래. 예를 들어, 응답 데이터 필터링, 그리고 더 중요한 것은 다양한 응답 오류 코드에 대한 통합 오류 처리, 네트워크 연결 끊김 처리 등이 있습니다. 🎜🎜여기서 403과 단절을 판단하겠습니다. 🎜rrreee🎜🎜또한 인터셉터에는 로딩과 같은 버퍼링 효과를 배치하는 것도 적합합니다. 🎜요청 인터셉터에 로딩을 표시하고 응답 인터셉터에서 로딩을 제거합니다. 이러한 방식으로 모든 요청은 통합된 <code>로드 효과를 갖습니다. 🎜
  • 기본적으로 새 인스턴스 내보내기
rrreee🎜🎜최종 완성 코드는 다음과 같습니다. 🎜🎜rrreee🎜이제 axios 캡슐화가 80% 완료되었습니다. . 처음에 설정한 캡슐화 목표를 달성하려면 Axios를 인터페이스와 결합하고 한 계층 더 캡슐화해야 합니다. 🎜🎜🎜3. 새로운 axios 패키지 API를 사용하세요🎜🎜
  • 在 src 目录下新建 api 文件夹。把所有涉及HTTP请求的接口统一集中到这个目录来管理。
  • 新建 home.js。我们需要把接口根据一定规则分好类,一类接口对应一个js文件。这个分类可以是按页面来划分,或者按模块等等。为了演示更直观,我这里就按页面来划分了。实际根据自己的需求来定。
  • 使用新的 axios 封装API(固定url的值,合并用户传过来的参数),然后命名导出这些函数。
// src/api/home.js 

import axios from &#39;@/utils/http&#39;;
export const fetchData = options => axios.request({
  ...options,
  url: &#39;/data&#39;,
});
export default {};

在 api 目录下新建 index.js,把其他文件的接口都在这个文件里汇总导出。

 // src/api/index.js
  
  export * from &#39;./home&#39;;

这层封装将我们的新的axios封装到了更简洁更语义化的接口方法中。

现在我们的目录结构长这样:

|--public/
|--mock/
|   |--db.json  # 接口模拟数据
|--src/
|   |--api/     # 所有的接口都集中在这个目录下
|       |--home.js  # Home页面里涉及到的接口封装在这里
|       |--index.js # 项目中所有接口调用的入口
|   |--assets/
|   |--components/
|   |--router/
|   |--store/
|   |--utils/
|       |--http.js  # axios封装在这里
|   |--views/
|       |--Home.Vue
|   |--App.vue
|   |--main.js
|   |--theme.styl
|--package.json
|...

4.使用封装后的axios

现在我们要发HTTP请求时,只需引入 api 下的 index.js 文件就可以调用任何接口了,并且用的是封装后的 axios。

// src/views/Home.vue

<template>
  <div class="home">
    <h1>This is home page</h1>
  </div>
</template>

<script>
// @ is an alias to /src
import { fetchData } from &#39;@/api/index&#39;;

export default {
  name: &#39;home&#39;,
  mounted() {
    fetchData()  // axios请求在这里
      .then((data) => {
        console.log(data);
      })
      .catch((err) => {
        console.log(err);
      });
  },
};
</script>

axios请求被封装在fetchData函数里,页面请求压根不需要出现任何axios API,悄无声息地发起请求获取响应,就像在调用一个简单的 Promise 函数一样轻松。并且在页面中只需专注处理业务功能,不用被其他事物干扰。

위 내용은 vue에서 axios의 캡슐화 요청을 구문 분석합니다(단계 코드 사용).의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 jb51.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제