在本教程中,我们将继续使用 Laravel 构建 Vue 单页应用程序 (SPA),学习如何在 Vue 组件中从 Laravel API 端点加载异步数据。我们还将探讨 API 响应返回错误时的错误处理以及如何在界面中进行响应。
如果你没有阅读 第一部分,我们介绍了使用 Vue 路由器和 Laravel 后端连接 Vue 单页应用程序 (SPA)。如果你想跟着做,你应该先阅读第一部分!
为了使服务器端数据保持简单,我们的 API 将使用假数据。在第三部分,我们将把 API 转换为控制器,测试数据将来自数据库。
API 路由
Vue SPA 应用程序是无状态的,这意味着我们向 Laravel 路由器发出 API 请求,我们的路由定义在 routes/api.php
中。API 路由不使用会话状态,这意味着我们的应用程序在后端确实是无状态的。
在我们的示例中,假设我们想要获取一个用户列表,以便我们可以演示从我们的 Vue 应用程序到后端的异步请求。
Route::get('/users', function () { return factory('App\User', 10)->make();});
我们的临时路由正在使用 模型工厂 来创建尚未持久保存到数据库的 Eloquent 模型集合。我们使用 make()
方法,该方法不会尝试将测试数据插入到数据库中,而是返回一个尚未持久保存的新 App\User
实例的集合。
在 routes/api.php
文件中定义路由意味着我们的请求有一个 /api
的前缀,这是因为应用程序的 RouteServiceProvider
类中定义了这个前缀。
protected function mapApiRoutes(){ Route::prefix('api') ->middleware('api') ->namespace($this->namespace) ->group(base_path('routes/api.php'));}
我们的用户资源是 GET /api/users
,一个示例响应可能如下所示:
[ { "name":"Roel Rosenbaum I", "email":"catharine.kreiger@example.net" }, { "name":"Prof. Clarissa Osinski", "email":"wilfrid.kiehn@example.com" }, { "name":"Myrtle Wyman", "email":"dan31@example.com" }, ...]
客户端路由
如果你按照第一部分进行操作,我们在 resources/assets/js/app.js
文件中构建了几个路由来演示在 SPA 中进行导航。每当我们想要添加一个新的路由时,我们都会在 routes
数组中创建一个新对象,这个对象定义了每个路由的路径、名称和组件。最后一个路由是我们的新 /users
路由。
import UsersIndex from './views/UsersIndex'; const router = new VueRouter({ mode: 'history', routes: [ { path: '/', name: 'home', component: Home }, { path: '/hello', name: 'hello', component: Hello, }, { path: '/users', name: 'users.index', component: UsersIndex, }, ],});
UsersIndex 组件
路由使用 UsersIndex
组件定义了一个路由;以下是该文件(位于 resources/assets/js/views/UsersIndex.vue
)的样子:
<template> <div class="users"> <div class="loading" v-if="loading"> Loading... </div> <div v-if="error" class="error"> {{ error }} </div> <ul v-if="users"> <li v-for="{ name, email } in users"> <strong>Name:</strong> {{ name }}, <strong>Email:</strong> {{ email }} </li> </ul> </div></template><script>import axios from 'axios';export default { data() { return { loading: false, users: null, error: null, }; }, created() { this.fetchData(); }, methods: { fetchData() { this.error = this.users = null; this.loading = true; axios .get('/api/users') .then(response => { console.log(response); }); } }}</script>
如果你不熟悉 Vue,这里可能有一些你不熟悉的概念。我建议阅读 Vue 组件 文档,并熟悉 Vue 生命周期钩子(created、mounted 等)。
在这个组件中,我们是在组件 created
钩子期间获取异步数据的。我们定义了一个 fechData()
方法,它将错误和用户属性重置为 null
,将 loading
设置为 true。
fetchData()
方法中的最后一行使用 Axios 库向我们的 Laravel API 发出 HTTP 请求。Axios 是一个基于 promise 的 HTTP 客户端,我们使用它来链接 then()
回调,我们将在其中记录响应,并最终将其设置为 users
数据属性。
以下是在应用程序中加载 /users
时控制台数据的样子(客户端页面,而不是 API):
我还想让你注意这里正在进行的 对象解构。
<li v-for="{ name, email } in users"> <strong>Name:</strong> {{ name }}, <strong>Email:</strong> {{ email }}</li>
对象解构是一种有效的方式,它只获取对象所需的内容,更简洁/可读。
完成路由组件
我们已经有了 /users
的路由和组件,让我们在主 App
组件中添加一个导航链接,然后设置 users
响应中的用户数据。
在 resources/assets/js/views/App.vue
中,添加一个使用我们为用户索引设置的路由名称的链接。
<template> <div> <h1>Vue Router Demo App</h1> <p> <router-link :to="{ name: 'home' }">Home</router-link> | <router-link :to="{ name: 'hello' }">Hello World</router-link> | <router-link :to="{ name: 'users.index' }">Users</router-link> </p> <div class="container"> <router-view></router-view> </div> </div></template><script> export default {}</script>
接下来,让我们更新 UsersIndex.vue
文件来设置用户数据。
fetchData() { this.error = this.users = null; this.loading = true; axios .get('/api/users') .then(response => { this.loading = false; this.users = response.data; });}
现在,如果你刷新页面,你应该看到如下内容:
处理错误
我们的组件在大多数情况下应该按预期工作,但我们还没有处理 API 错误。让我们在 API 端点中添加一个模拟服务器错误。
Route::get('/users', function () { if (rand(1, 10) < 3) { abort(500, 'We could not retrieve the users'); } return factory('App\User', 10)->make();});
我们使用 rand()
来在数字小于 3 时中止请求。如果你刷新页面几次,你应该会看到“加载中...”,并且如果你检查开发工具,你将看到 Axios 请求发出的未捕获异常。
我们可以通过在 Axios promise 上链接 catch()
回调来处理失败的请求。
fetchData() { this.error = this.users = null; this.loading = true; axios .get('/api/users') .then(response => { this.loading = false; this.users = response.data; }).catch(error => { this.loading = false; this.error = error.response.data.message || error.message; });}
我们将加载数据属性设置为 false
,并使用错误异常来尝试设置来自响应的 message
键。如果找不到 message
键,则会回退到 exception.message
属性。
为了保险起见,让我们在 UsersIndex.vue
模板中为用户提供一个“重试”按钮,该按钮会简单地调用我们的 fetchData
方法来刷新 users
属性。
<div v-if="error" class="error"> <p>{{ error }}</p> <p> <button @click.prevent="fetchData"> Try Again </button> </p></div>
现在,如果出现故障,UI 应该如下所示:
结论
在这篇简短的文章中,我们添加了一条新路由,用于从无状态 Laravel API 端点列出一些虚拟用户。我们使用了“导航后”数据获取策略来获取数据。或者换句话说,我们在创建组件时向 API 请求数据。
在 第三部分,我们将探讨在 Vue 路由器中使用回调在导航到组件之前获取数据,向你展示如何在渲染路由视图之前获取数据。
我们还将把 API 转换为使用具有种子数据的数据库表,这样我们就可以继续导航到单个用户,这涵盖了使用路由参数。
现在,让我们继续学习使用 Laravel 构建 Vue SPA 应用的 第三部分!