TypeScript入门 (五)异步编程与前后端交互

news2024/9/28 7:24:31

head-bar

引言

大家好,我是GISer Liu😁,一名热爱AI技术的GIS开发者。本系列文章是我跟随DataWhale 2024年9月学习赛的TypeScript学习总结文档。本文旨在全面介绍 TypeScript 中的异步编程与网络请求,帮助读者深入理解 TypeScript 中的 async/await、Promise、Fetch API、Axios、请求拦截器、响应拦截器、跨域处理等概念,以及在实际开发中的应用。💕💕😊


介绍

1.异步编程

在现代 Web 开发中,异步编程已经成为不可或缺的一部分。无论是从服务器获取数据、处理用户输入,还是执行复杂的计算任务,异步编程都能显著提升应用的性能和用户体验。

想象一下,如果一个网页在加载数据时需要等待所有操作完成才能继续,用户将会面临长时间的等待和卡顿,这显然是不可接受的。

异步编程的核心思想是允许程序在等待某些操作完成的同时,继续执行其他任务。这种方式不仅提高了程序的响应速度,还避免了因长时间等待而导致的资源浪费。

在 JavaScript 生态系统中,异步编程尤为重要,因为它是一种单线程语言,如果不采用异步机制,程序很容易陷入阻塞状态。

在TypeScript中,我们主要通过Promise和async/await进行一步编程,后者是前者的简化语法糖,具体内容我们在对应模块中进行详细介绍;

2.网络请求

在当下主流 Web 应用开发中,网络请求是获取和发送数据的重要手段。无论是从服务器获取数据,还是向服务器提交表单,网络请求都是不可或缺的。

在 TypeScript 中,常用的网络请求方法包括 XHRfetchaxios。它们的本质都是通过 HTTP 协议与服务器进行通信。fetchaxios 都基于 Promise,支持异步操作,使得我们可以使用 async/await 来简化异步代码的编写。

网络请求常常和异步编程相伴出现;这里作者联合两者,读者可以有一个更好的理解;

下面作者将两个模块分别进行描述!😘


一. TypeScript 中的异步编程模块

1.TypeScript 编译器与 ES5 标准

① TypeScript 默认使用 ES5 标准

TypeScript 是一种强类型的 JavaScript 超集,它通过编译器将 TypeScript 代码转换为 JavaScript 代码。默认情况下,TypeScript 编译器会将代码编译为 ES5 标准,以确保生成的 JavaScript 代码在大多数现代浏览器中都能正常运行。

ES5(ECMAScript 5)是 JavaScript 的一个早期标准,发布于 2009 年。尽管 ES5 提供了许多基础功能,但它并不包含一些现代 JavaScript 特性,如 Promise 对象和 async/await 语法。

② ES5 标准中不包含 Promise 对象

在 ES5 标准中,JavaScript 并没有内置的 Promise 对象Promise 是 ES6(ECMAScript 2015)引入的一个重要特性,用于处理异步操作。Promise 提供了一种更优雅的方式来处理异步操作的结果和错误,避免了传统的回调函数嵌套(即回调地狱)。

由于 TypeScript 默认编译为 ES5,因此在编写 TypeScript 代码时,如果需要使用 Promise,通常需要确保编译目标为 ES6 或更高版本。可以通过在 tsconfig.json 文件中设置 target 属性来指定编译目标:

{
  "compilerOptions": {
    "target": "ES6"
  }
}

2. async/await 简介

async/await 是 ES2017(ES8)的特性

async/await 是 ES2017(ES8)引入的语法特性,它建立在 Promise 之上,旨在进一步简化异步编程。async/await 允许开发者以同步代码的方式编写异步操作,从而提高代码的可读性和可维护性。

  • async 关键字用于声明一个异步函数,
  • await 关键字用于等待一个 Promise 的解析结果。
  • await 只能在 async 函数内部使用,它会使函数暂停执行,直到 Promise 被解析或拒绝。
async/await 如何简化异步编程

async/await 的主要优势在于它能够将异步代码转换为看起来像同步代码的形式,从而避免了回调地狱和复杂的 Promise 链式调用。以下是一个简单的示例,展示了如何使用 async/await 来处理异步操作:

// 定义一个返回 Promise 的异步函数
async function fetchData(): Promise<string> {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve("Data fetched successfully!");
    }, 1000);
  });
}

// 使用 async/await 调用异步函数
async function main() {
  try {
    const result = await fetchData();
    console.log(result); // 输出: Data fetched successfully!
  } catch (error) {
    console.error("Error fetching data:", error);
  }
}

main();

其中,fetchData 函数返回一个 Promise,模拟了一个异步操作。在 main 函数中,我们使用 await 关键字等待 fetchData 的结果,并将其赋值给 result 变量。如果 fetchData 成功,result 将包含解析后的值;如果失败,错误将被捕获并在 catch 块中处理。


3.使用 async/await 实现异步操作

①处理异步操作的延迟

在实际开发中,异步操作通常涉及网络请求、文件读取等需要时间完成的任务。我们可以使用 setTimeout 来模拟这些延迟操作。

// 定义一个返回 Promise 的异步函数,模拟延迟操作
async function asyncOperation(): Promise<number> {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(10);
    }, 1000);  // 延迟 1000 毫秒(1 秒)
  });
}

// 使用 async/await 调用异步函数
async function run() {
  const result = await asyncOperation();
  console.log(result);  // 输出: 10
}

run();

asyncOperation 函数返回一个 Promise,该 Promise 会在 1000 毫秒后解析并返回数字 10

run 函数中,我们使用 await 关键字等待 asyncOperation 的结果。await 会使 run 函数暂停执行,直到 asyncOperation 返回的 Promise 被解析。一旦 Promise 被解析,result 变量将包含解析后的值,即 10

②串行执行多个异步操作

在某些场景下,我们需要按顺序执行多个异步操作,例如预先加载多个数据。await 关键字可以确保这些操作按顺序执行,即在前一个操作完成后再执行下一个操作。

// 定义两个返回 Promise 的异步函数,模拟延迟操作
async function asyncOperation1(): Promise<number> {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(10);
    }, 1000);  // 延迟 1000 毫秒(1 秒)
  });
}

async function asyncOperation2(): Promise<number> {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(20);
    }, 1000);  // 延迟 1000 毫秒(1 秒)
  });
}

// 使用 async/await 串行执行多个异步操作
async function run() {
  const result1 = await asyncOperation1();
  const result2 = await asyncOperation2();
  console.log(result1 + result2);  // 输出: 30
}

run();

这里我们定义了两个异步函数 asyncOperation1asyncOperation2,它们分别返回一个 Promise,并在 1000 毫秒后解析。在 run 函数中,我们使用 await 关键字按顺序等待这两个异步操作的结果。await 确保 asyncOperation1 完成后才会执行 asyncOperation2,从而实现了串行执行。

通过这种方式可以避免数据还没有加载就执行了数据展示或处理的程序引发的报错!

③ 处理异步操作中的错误

在异步操作中,错误处理是非常重要的。我们可以使用 try...catch 块来捕获和处理异步操作中的错误。

// 定义一个返回 Promise 的异步函数,模拟可能出错的异步操作
async function asyncOperation(): Promise<number> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject(new Error("Something went wrong"));
    }, 1000);  // 延迟 1000 毫秒(1 秒)
  });
}

// 使用 async/await 调用异步函数,并使用 try...catch 块捕获错误
async function run() {
  try {
    const result = await asyncOperation();
    console.log(result);
  } catch (error) {
    console.error(error.message);  // 输出: Something went wrong
  }
}

run();

asyncOperation 函数返回一个 Promise,该 Promise 会在 1000 毫秒后被拒绝,并抛出一个错误。在 run 函数中,我们使用 try...catch 块来捕获这个错误。如果 asyncOperation 成功,result 变量将包含解析后的值;如果失败,错误将被捕获并在 catch 块中处理。

错误处理在异步编程中非常重要,因为它可以帮助我们及时发现和处理潜在的问题,避免程序崩溃或产生不可预期的行为。

二、TypeScript中的网络请求模块

1. 网络请求的基本原理

① HTTP 协议

HTTP(Hypertext Transfer Protocol)是一种用于在网络上传输超文本文档的协议。它定义了客户端和服务器之间的通信规范,包括请求格式、响应格式、请求方法、状态码等

② 请求方法

HTTP 协议定义了几种常见的请求方法,其中最常用的是 GET 和 POST。

  • GET 请求:用于从服务器获取数据。GET 请求的参数会附加在 URL 后面,因此不适合传递敏感信息。
  • POST 请求:用于向服务器发送数据。POST 请求的参数会放在请求体中,因此适合传递敏感信息和大量数据。
③ 状态码

HTTP 状态码用于表示请求的处理结果。常见的状态码包括:

  • 2xx:成功状态码,表示请求成功。例如,200 OK 表示请求成功。
  • 3xx:重定向状态码,表示需要进一步操作才能完成请求。例如,301 Moved Permanently 表示资源已永久移动。
  • 4xx:客户端错误状态码,表示客户端请求有误。例如,404 Not Found 表示请求的资源不存在。
  • 5xx:服务器错误状态码,表示服务器处理请求时出错。例如,500 Internal Server Error 表示服务器内部错误。

2. Fetch API 的使用

Fetch API 是一个现代化的网络请求 API,它基于 Promise,可以用于发送和接收网络请求。

① Fetch API 的基本用法
fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

这里我们分析一下这个过程:

1.创建请求:使用 fetch 函数创建一个请求。

2.发送请求fetch 函数会发送请求到指定的 URL。

3.接收响应:服务器返回响应后,fetch 函数会返回一个 Response 对象。

4.处理响应:通过 Response 对象的方法(如 json())处理响应数据,将数据转化为json格式方便处理。

5.输出或抛出错误:如果数据如期解析成功,就会在控制台输出数据,如果报错则会输出错误;

② Fetch API 的优缺点
  • 优点:语法简单、基于 Promise、支持跨域请求、支持流数据。
  • 缺点兼容性不佳、缺乏细节控制、只能捕获网络错误

3. Axios 的使用

Axios 是一个基于 Promise 的 HTTP 客户端,广泛用于浏览器和 Node.js 环境中。

①Axios 的基本用法
import axios from 'axios';

axios.get('https://api.example.com/data')
  .then(response => console.log(response.data))
  .catch(error => console.error('Error:', error));
② Axios 的请求流程
  1. 创建请求:使用 axios 函数创建一个请求。
  2. 发送请求axios 函数会发送请求到指定的 URL。
  3. 接收响应:服务器返回响应后,axios 函数会返回一个包含响应数据的 Promise。
  4. 处理响应:通过 .then() 方法处理响应数据。
③ Axios 的配置选项

Axios 提供了丰富的配置选项,可以用于自定义请求的行为。

axios({
  method: 'post',
  url: 'https://api.example.com/data',
  data: {
    firstName: 'John',
    lastName: 'Doe'
  }
}).then(response => console.log(response.data))
  .catch(error => console.error('Error:', error));
④ Axios 的拦截器

Axios 支持请求拦截器和响应拦截器,可以在请求发送前或响应返回后进行额外的处理。

4. 请求拦截器与响应拦截器

①请求拦截器

请求拦截器允许我们在请求发送前对请求配置进行修改或添加额外的逻辑。常见的使用场景包括:

  • 添加认证信息:在请求头中添加认证信息(如 JWT Token)。
  • 设置全局请求头:为所有请求设置相同的请求头(如 Content-Type)。
  • 请求日志记录:记录请求的详细信息,便于调试和监控。
  • 请求重试:在请求失败时自动重试。

假设我们有一个需要认证的 API,每次请求都需要在请求头中添加 JWT Token。通过请求拦截器,我们可以在每次请求前自动添加 Token,而不需要在每个请求中手动设置。

代码如下:

import axios from 'axios';

// 创建一个 Axios 实例
const instance = axios.create({
  baseURL: 'https://api.example.com', //设置基础 URL 和最大请求超时时间。
  timeout: 10000,
});

// 添加请求拦截器
instance.interceptors.request.use(
  (config) => {
    // 在发送请求之前做些什么
    const token = localStorage.getItem('token'); // 在请求发送前,从 localStorage 中获取 Token,并将其添加到请求头中。然后记录请求配置信息
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    console.log('Request Config:', config);
    return config;
  },
  (error) => {
    // 对请求错误做些什么
    console.error('Request Error:', error);
    return Promise.reject(error);
  }
);

// 发送请求
instance.get('/data')
  .then(response => console.log(response.data))
  .catch(error => console.error('Error:', error));

请求拦截器就讲到这里,更多应用还是得实践尝试!

② 响应拦截器

响应拦截器允许我们在响应返回后对响应数据进行处理或添加额外的逻辑。常见的使用场景包括:

  • 统一处理响应数据:对响应数据进行格式化或解密。
  • 错误处理:统一处理服务器返回的错误信息。
  • 响应日志记录:记录响应的详细信息,便于调试和监控。
  • 权限校验:在响应中检查用户权限,并根据权限进行相应的操作。

假设我们的 API 返回的数据格式是 JSON,但在某些情况下,服务器可能会返回错误信息。通过响应拦截器,我们可以在响应返回后统一处理错误信息,并根据错误类型进行相应的操作。

下面是个代码案例:

import axios from 'axios';

// 创建一个 Axios 实例
const instance = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000,
});

// 添加响应拦截器
instance.interceptors.response.use(
  (response) => {
    // 对响应数据做点什么
    console.log('Response Data:', response.data);
    return response.data;
  },
  (error) => {
    // 对响应错误做点什么
    if (error.response) {
      // 服务器返回了错误响应
      console.error('Server Error:', error.response.data);
      switch (error.response.status) {
        case 401:
          // 未授权,跳转到登录页面
          window.location.href = '/login';
          break;
        case 404:
          // 资源未找到,显示错误信息
          console.error('Resource Not Found');
          break;
        default:
          // 其他错误,显示通用错误信息
          console.error('An error occurred');
      }
    } else if (error.request) {
      // 请求已发送但未收到响应
      console.error('No Response Received:', error.request);
    } else {
      // 其他错误
      console.error('Request Error:', error.message);
    }
    return Promise.reject(error);
  }
);

// 发送请求
instance.get('/data')
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));
  • 成功回调:在响应返回后,记录响应数据并返回处理后的数据。
  • 错误回调:在响应发生错误时,根据错误类型进行相应的处理:
  • 服务器返回错误响应:根据状态码进行不同的处理(如 401 跳转到登录页面,404 显示资源未找到信息)。
  • 请求已发送但未收到响应:记录未收到响应的请求信息。
  • 其他错误:记录请求错误信息。

三、案例实践

这里作者基于实现一个全栈案例Demo,下面是技术栈:

  • 前端:Vue3 +TypeScript
  • 后端:FastAPI + Python
  • 网络请求:Axios

1 环境搭建

① 项目创建

Vite 是一个现代化的前端构建工具,它提供了快速的开发体验。我们可以使用 Vite 快速创建一个 Vue 3 + TypeScript 项目。

  1. 安装 Vite
npm install -g create-vite
  1. 创建vite项目
npm create vite
  1. 选择项目模板

  1. 选择 TypeScript 支持

  1. 进入项目目录并安装依赖

② 项目启动

安装完依赖后,可以使用以下命令启动开发服务器:

npm run dev

启动成功!

2. 单文件组件(SFC)

① 介绍 Vue 的单文件组件(SFC)

Vue 的单文件组件(SFC)是一种将模板、逻辑和样式封装在一个文件中的组件格式。SFC 使用 .vue 文件扩展名,通常包含以下三个部分:

  • <template>:定义组件的 HTML 模板。
  • <script>:定义组件的逻辑,通常使用 TypeScript。
  • <style>:定义组件的样式。

如下图中APP.vue文件内容所示;

② 展示 HelloWorld.vue 组件的代码
<template>
  <div class="hello">
    <h1>{{ msg }}</h1>

  </div>

</template>

<script lang="ts">
import { defineComponent } from 'vue';

export default defineComponent({
  name: 'HelloWorld',
  props: {
    msg: {
      type: String,
      required: true,
    },
  },
});
</script>

<style scoped>
.hello {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

3. 引入 Axios 进行网络请求

① 在 TypeScript 中使用 Axios 进行网络请求

首先,我们需要安装 Axios:

npm install axios
② 发起 GET 和 POST 请求

在 Vue 组件中使用 Axios 发起 GET 和 POST 请求:

<template>
  <div>
    <h1>Axios 案例测试</h1>

    <button @click="fetchPosts">获取100篇文章数据</button>
    <button @click="fetchPostById">根据文章ID获取文章数据</button>
    <button @click="addPost">添加文章</button>

    <button @click="fetchCatImage">随机获取1张猫图</button>
    <button @click="fetchDogImage">随机返回一张狗子照片</button>
    <button @click="fetchRandomImage">返回随机图片</button>

    <div v-if="data">
      <pre>{{ data }}</pre>
    </div>

    <div v-if="imageUrl">
      <img :src="imageUrl" alt="图片" />
    </div>

    <div v-if="quote">
      <p>{{ quote }}</p>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import axios from 'axios';

export default defineComponent({
  name: 'AxiosExample',
  data() {
    return {
      data: null,
      imageUrl: null,
      quote: null,
    };
  },
  methods: {
    async fetchPosts() {
      try {
        const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
        this.data = JSON.stringify(response.data, null, 2);
      } catch (error) {
        console.error('获取文章数据失败:', error);
      }
    },
    async fetchPostById() {
      try {
        const response = await axios.get('https://jsonplaceholder.typicode.com/posts/2');
        this.data = JSON.stringify(response.data, null, 2);
      } catch (error) {
        console.error('获取指定文章数据失败:', error);
      }
    },
    async addPost() {
      try {
        const response = await axios.post('https://jsonplaceholder.typicode.com/posts', {
          title: 'foo',
          body: 'bar',
          userId: 1,
        });
        this.data = JSON.stringify(response.data, null, 2);
      } catch (error) {
        console.error('添加文章失败:', error);
      }
    },
    async fetchCatImage() {
      try {
        const response = await axios.get('https://api.thecatapi.com/v1/images/search?limit=1');
        this.imageUrl = response.data[0].url;
      } catch (error) {
        console.error('获取猫图失败:', error);
      }
    },
    async fetchDogImage() {
      try {
        const response = await axios.get('https://dog.ceo/api/breeds/image/random');
        this.imageUrl = response.data.message;
      } catch (error) {
        console.error('获取狗子照片失败:', error);
      }
    },
    async fetchRandomImage() {
      try {
        const response = await axios.get('https://picsum.photos/200/300');
        this.imageUrl = response.request.responseURL;
      } catch (error) {
        console.error('获取随机图片失败:', error);
      }
    },
  },
});
</script>

<style scoped>
/* 你可以在这里添加一些样式 */
</style>

这里由于时间问题,UI相对还是有点粗糙;😂

当然我们这里成功加载了一些公共服务的API,我们也可以自己搭建后端获取数据,下面我们简单介绍一下使用Python语言基于FastAPI框架进行后端搭建的Demo;

4. 使用 FastAPI 搭建后端服务

① 安装和配置 FastAPI

FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API。我们可以使用 FastAPI 快速搭建一个后端服务。

  1. 安装 FastAPI 和 Uvicorn
pip install fastapi uvicorn
  1. 创建一个简单的 FastAPI 应用
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# 添加 CORS 中间件,避免跨域错误
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # 允许所有来源
    allow_credentials=True,
    allow_methods=["*"],  # 允许所有方法
    allow_headers=["*"],  # 允许所有头
)

@app.get("/data")
async def get_data():
    return {"message": "Hello, World!"}

@app.post("/data")
async def add_data(name: str, age: int):
    return {"name": name, "age": age}
  1. 启动 FastAPI 服务:这里文件名为 main.py
uvicorn main:app --reload 

② 后端测试代码

我们可以使用 Postman 或 curl 测试后端服务:

  • GET 请求
curl http://127.0.0.1:8000/data

  • POST 请求
curl.exe -X POST "http://127.0.0.1:8000/data?name=John%20Doe&age=30"

③ 前端与后端的交互

在 Vue 组件中使用 Axios 与 FastAPI 后端进行交互:

这里我们将刚刚的get测试和post测试也加入到vue3程序中;

<template>
  <div>
    <h1>Axios 案例测试</h1>

    <button @click="fetchPosts">获取100篇文章数据</button>
    <button @click="fetchPostById">根据文章ID获取文章数据</button>
    <button @click="addPost">添加文章</button>

    <button @click="fetchCatImage">随机获取1张猫图</button>
    <button @click="fetchDogImage">随机返回一张狗子照片</button>
    <button @click="fetchRandomImage">返回随机图片</button>

    <button @click="fetchLocalData">获取本地数据</button>
    <button @click="addLocalData">添加本地数据</button>

    <div v-if="data">
      <pre>{{ data }}</pre>
    </div>

    <div v-if="imageUrl">
      <img :src="imageUrl" alt="图片" />
    </div>

    <div v-if="quote">
      <p>{{ quote }}</p>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import axios from 'axios';

export default defineComponent({
  name: 'AxiosExample',
  data() {
    return {
      data: null,
      imageUrl: null,
      quote: null,
    };
  },
  methods: {
    async fetchPosts() {
      try {
        const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
        this.data = JSON.stringify(response.data, null, 2);
      } catch (error) {
        console.error('获取文章数据失败:', error);
      }
    },
    async fetchPostById() {
      try {
        const response = await axios.get('https://jsonplaceholder.typicode.com/posts/2');
        this.data = JSON.stringify(response.data, null, 2);
      } catch (error) {
        console.error('获取指定文章数据失败:', error);
      }
    },
    async addPost() {
      try {
        const response = await axios.post('https://jsonplaceholder.typicode.com/posts', {
          title: 'foo',
          body: 'bar',
          userId: 1,
        });
        this.data = JSON.stringify(response.data, null, 2);
      } catch (error) {
        console.error('添加文章失败:', error);
      }
    },
    async fetchCatImage() {
      try {
        const response = await axios.get('https://api.thecatapi.com/v1/images/search?limit=1');
        this.imageUrl = response.data[0].url;
      } catch (error) {
        console.error('获取猫图失败:', error);
      }
    },
    async fetchDogImage() {
      try {
        const response = await axios.get('https://dog.ceo/api/breeds/image/random');
        this.imageUrl = response.data.message;
      } catch (error) {
        console.error('获取狗子照片失败:', error);
      }
    },
    async fetchRandomImage() {
      try {
        const response = await axios.get('https://picsum.photos/200/300');
        this.imageUrl = response.request.responseURL;
      } catch (error) {
        console.error('获取随机图片失败:', error);
      }
    },
    async fetchLocalData() {
      try {
        const response = await axios.get('http://127.0.0.1:8000/data');
        this.data = JSON.stringify(response.data, null, 2);
      } catch (error) {
        console.error('获取本地数据失败:', error);
      }
    },
    async addLocalData() {
      try {
        const response = await axios.post('http://127.0.0.1:8000/data?name=John Doe&age=30');
        this.data = JSON.stringify(response.data, null, 2);
      } catch (error) {
        console.error('添加本地数据失败:', error);
      }
    },
  },
});
</script>

<style scoped>
/* 你可以在这里添加一些样式 */
</style>

经过测试,获取成功!!

如果存在网络问题,看看是不是后端没有配置跨域CORS中间件或者后端项目是否启动;

5. 封装 Axios (可选)

①为什么要封装 Axios

Axios 可以带来以下好处:

  • 代码复用:将常用的请求逻辑封装起来,避免重复代码。
  • 统一配置:统一管理请求的配置,如基础 URL、请求头、拦截器等。
  • 错误处理:统一处理请求错误,减少重复的错误处理逻辑。
  • 类型安全:使用 TypeScript 定义接口类型,提升代码的类型安全性。
② 代码实践
  • 在 base.ts 文件中创建 Axios 实例

创建一个 base.ts 文件,用于创建 Axios 实例并设置请求和响应拦截器:

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';

const instance: AxiosInstance = axios.create({
  baseURL: 'http://127.0.0.1:8000',
  timeout: 10000,
});

// 请求拦截器
instance.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

// 响应拦截器
instance.interceptors.response.use(
  (response: AxiosResponse) => {
    return response.data;
  },
  (error) => {
    return Promise.reject(error);
  }
);

export default instance;
③ 定义接口类型

创建一个 type.ts 文件,用于定义接口类型:

export interface DataResponse {
  message: string;
}

export interface CreateDataRequest {
  name: string;
  age: number;
}

export interface CreateDataResponse {
  name: string;
  age: number;
}

通过定义接口类型,我们可以在编写代码时获得 TypeScript 的类型检查功能,减少类型错误。

④ 封装请求方法

创建一个 api.ts 文件,用于封装请求方法:

import axios from './base';
import { DataResponse, CreateDataRequest, CreateDataResponse } from './type';

export const fetchData = async (): Promise<DataResponse> => {
  const response = await axios.get<DataResponse>('/data');
  return response;
};

export const createData = async (data: CreateDataRequest): Promise<CreateDataResponse> => {
  const response = await axios.post<CreateDataResponse>('/data', data);
  return response;
};

api.ts 文件中,我们封装了 fetchDatacreateData 方法,并在方法中使用 TypeScript 的类型注解,确保请求和响应的类型安全。

⑤ 在组件中使用封装的 Axios

在 Vue 组件中直接使用封装的请求方法:

<template>
  <div>
    <h1>API Example</h1>

    <button @click="fetchData">Fetch Data</button>

    <button @click="sendData">Send Data</button>

    <div v-if="data">
      <pre>{{ data }}</pre>

    </div>

  </div>

</template>

<script lang="ts">
import { defineComponent } from 'vue';
import { fetchData, createData } from './api';

export default defineComponent({
  name: 'APIExample',
  data() {
    return {
      data: null,
    };
  },
  methods: {
    async fetchData() {
      try {
        this.data = await fetchData();
      } catch (error) {
        console.error('Error fetching data:', error);
      }
    },
    async sendData() {
      try {
        this.data = await createData({ name: 'John Doe', age: 30 });
      } catch (error) {
        console.error('Error sending data:', error);
      }
    },
  },
});
</script>

在 Vue 组件的方法中,我们可以直接使用 await 关键字调用封装的请求方法,简化异步代码的编写。

⑥ 使用 async/await 处理请求

在 Vue 组件的方法中使用 async/await 处理请求:

methods: {
  async fetchData() {
    try {
      this.data = await fetchData();
    } catch (error) {
      console.error('Error fetching data:', error);
    }
  },
  async sendData() {
    try {
      this.data = await createData({ name: 'John Doe', age: 30 });
    } catch (error) {
      console.error('Error sending data:', error);
    }
  },
}

async 函数中,我们可以使用 await 关键字等待异步操作完成,并将结果赋值给组件的 data 属性。通过这种方式,我们可以更简洁地处理异步请求。


Over,作者的总结完毕!😘👌😊 本次学习总结到此结束!!🙂 各位读者可以参考本文通过代码实践来加深理解!😉

相关链接

  • 项目地址:TypeScript-CookBook
  • 相关文档:专栏地址
  • 作者主页:GISer Liu-CSDN博客

thank_watch

如果觉得我的文章对您有帮助,三连+关注便是对我创作的最大鼓励!或者一个star🌟也可以😂.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2172810.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Colorful/七彩虹将星X17 XS 22 Win11原厂OEM系统 带COLORFUL一键还原

安装完毕自带原厂驱动和预装软件以及一键恢复功能&#xff0c;自动重建COLORFUL RECOVERY功能&#xff0c;恢复到新机开箱状态。 【格式】&#xff1a;iso 【系统类型】&#xff1a;Windows11 原厂系统下载网址&#xff1a;http://www.bioxt.cn 注意&#xff1a;安装系统会…

Redis 五大基本数据类型及其应用场景进阶(缓存预热、雪崩 、穿透 、击穿)

Redis 数据类型及其应用场景 Redis 是什么? Redis是一个使用C语言编写的高性能的基于内存的非关系型数据库&#xff0c;基于Key/Value结构存储数据&#xff0c;通常用来 缓解高并发场景下对某一资源的频繁请求 &#xff0c;减轻数据库的压力。它支持多种数据类型,如字符串、…

Linux安装JDK及配置环境变量超详细教程

微服务Linux解析部署使用全流程 linux系统的常用命令 Linux安装vim超详细教程 Linux安装tomcat及配置环境变量超详细教程 1、上传压缩包 统一创建目录&#xff1a;/usr/local/jdk&#xff0c;将压缩包上传到这个目录下。拖动文件到这个目录下即可。 2、执行解压命令 先进…

ELMO理论

目录 1 优点 2 缺点 3.知识点个人笔记 2018年3月份&#xff0c;ELMo出世&#xff0c;该paper是NAACL18 Best Paper。在之前2013年的word2vec及2014年的GloVe的工作中&#xff0c;每个词对应一个vector&#xff0c;对于多义词无能为力。ELMo的工作对于此&#xff0c;提出了一…

在 Gitlab 中使用 ChatGPT 进行 CodeReview

ChatGPT集成Gitlab&#xff0c;实现自动代码审计并进行评论&#xff0c;为软件开发团队提供高效、智能的代码审查解决方案。支持其他模型如通义千问等 自动触发与及时响应&#xff1a;利用Gitlab的Webhook功能&#xff0c;实现代码提交、合并请求和标签创建等事件的自动触发。一…

安全帽检测系统丨OPENAIGC开发者大赛高校组AI创作力奖

在第二届拯救者杯OPENAIGC开发者大赛中&#xff0c;涌现出一批技术突出、创意卓越的作品。为了让这些优秀项目被更多人看到&#xff0c;我们特意开设了优秀作品报道专栏&#xff0c;旨在展示其独特之处和开发者的精彩故事。 无论您是技术专家还是爱好者&#xff0c;希望能带给…

国产化低功耗低延时广覆盖物联网无线通讯方案_LAKI模组

01 物联网系统中为什么要使用LAKI模组。 物联网系统中使用LAKI模组的原因可以归结为以下几个方面&#xff1a; 技术先进性 广覆盖能力&#xff1a;LAKI模组具有卓越的广覆盖能力&#xff0c;其射频SoC芯片接收灵敏度小于-120dBm125kbps&#xff0c;系统通讯距离可达5千米以上…

一款好用的多种格式电子书制作软件

在数字化阅读日益普及的今天&#xff0c;电子书已经成为人们日常生活中不可或缺的一部分。而一款功能强大、操作简便的电子书制作软件&#xff0c;无疑是满足广大用户需求的最佳选择。 这款软件名为“FLBOOK在线制作电子杂志平台”&#xff0c;它支持多种格式输入&#xff0c;如…

设计模式、系统设计 record part02

软件设计模式&#xff1a; 1.应对重复发生的问题 2.解决方案 3.可以反复使用 1.本质是面向对象 2.优点很多 1.创建型-创建和使用分离 2.结构型-组合 3.行为型-协作 571123种模式 UML-统一建模语言-Unified Modeling Language 1.可视化&#xff0c;图形化 2.各种图&#xff08;9…

Python编程:08- pycharm使用技巧

新建文件时,自动填充代码 设置方法&#xff1a; settings→editor→file and code templates,选择python script #${NAME} 文件名 #${DATE} 日期自动补齐 if name ‘main’: # 先输入main,然后按tab键自动补齐自定义的段落 settings→editor→live templates,在右侧点击号…

C语言进阶版第12课—字符函数和字符串函数1

文章目录 1. 字符分类函数1.1 库函数iscntrl1.2 库函数isspace1.3 库函数islower和isupper 2. 字符转换函数3. strlen函数的使用和模拟实现3.1 strlen函数的使用3.2 strlen函数的模拟实现 4. strcpy函数的使用和模拟实现4.1 strcpy函数的使用4.2 strcpy函数的模拟实现 5. strca…

manim页面中不规则分割整个人页面。

界面中的分割方式 在信息设计中&#xff0c;我们常常需要通过分割设计的方式来对信息进行分组&#xff0c;界面中的分割方式大致分为三种&#xff1a;卡片、线条、留白。 界面中的分割方式主要可以分为以下几种&#xff1a; 一、根据规则进行分割&#xff1a; 规则网格分割&…

Starrocks with 嵌套

在某些场景下需要进行 with 嵌套 需要以下进行处理&#xff0c;报如图错误 with abc as (select * from .. ) insert into xxx select * from abc尝试创建物化视图 CREATE MATERIALIZED VIEW IF NOT EXISTS ads_test.xxx_mv REFRESH DEFERRED MANUAL AS with abc as (select…

C#基于SkiaSharp实现印章管理(9)

将印章设计模块设计的印章保存为图片并集中存放在指定文件夹内。新建印章应用项目&#xff0c;主要实现对图片及PDF文件加盖印章功能。本文实现给图片加盖印章功能。   给图片加盖印章的逻辑比较简单&#xff0c;就是将印章图片绘制到图片指定位置&#xff0c;使用SKControl控…

如何选择数据库架构

选择合适的数据库架构是一个复杂的过程&#xff0c;它取决于多种因素&#xff0c;包括应用程序的需求、数据量的大小、并发访问量、数据一致性要求、预算以及技术团队的熟悉程度等。以下是一些关键的步骤和考虑因素&#xff0c;帮助你选择合适的数据库架构&#xff1a; 1. 分析…

JITWatch安装使用方法

JITWatch 版本1.4.2 JDK 版本 11以上 1.下载JITWatch&#xff1a; https://github.com/AdoptOpenJDK/jitwatch/releases/download/1.4.2/jitwatch-ui-1.4.2-shaded-win.jar 2.启动 bat脚本执行&#xff1a;通过启动jar包方式启动JITWatch echo off start cmd /c "ti…

人工智能 实验1 Python语法

我发现了有些人喜欢静静看博客不聊天呐&#xff0c; 但是ta会点赞。 这样的人呢帅气低调有内涵&#xff0c; 美丽大方很优雅。 说的就是你&#xff0c; 不用再怀疑哦 实验1 Python语言基础一 【实验目的】掌握Python及其集成开发环境的下载安装及其简单应用 【实验内容…

结合了LLM(大语言模型)的编辑器,不仅能理解人类语言,还能与用户互动,仿佛有了自己的思想。...

从前有一个神奇的编辑器王国&#xff0c;那里住着各种编辑器&#xff1a;开源的、AI代码编辑器、视频编辑器&#xff0c;还有专门处理邮件和音频的编辑器。一天&#xff0c;国王Markdown决定举办一场盛会&#xff0c;邀请所有编辑器展示各自的才华。 开源编辑器们自豪地展示了他…

解决hbase和hadoop的log4j依赖冲突的警告

一、运行hbase的发现依赖冲突的警告 这警告不影响使用 二、重命名log4j文件 进入HBase的lib包下&#xff0c;将HBase的log4j文件重命名&#xff0c;改成备份&#xff0c;这样再次运行hbase的时候&#xff0c;就没有依赖冲突了。 三、冲突成功解决

数据分析工具julius ai如何使用

什么是julius ai Julius AI 是一款强大的ai数据分析工具。用户可以使用excel、数据库、文本文件等多种格式的数据&#xff0c;Julius AI 会自动分析这些数据并提供详细的解释和可视化图表。官网显示它目前已经有三十万用户。它也支持手机版。 虽然openai也支持生成图表&#xf…