前端拦截器

一个项目学会vue全家桶+axios实现登录、拦截、登出功能,以及利用axios的http拦截器拦截请求和响应。

前言

该项目是利用了Github 提供的personal token作为登录token,通过token访问你的Repository List。通过这个项目学习如何实现一个前端项目中所需要的 登录及拦截、登出、token失效的拦截及对应 axios 拦截器的使用。

准备

你需要先生成自己的 Github Personal Token(生成Token)。 Token 生成后 访问 Demo,即可查看你的Repository List。

项目结构

.
├── README.md
├── dist  // 打包构建后的文件夹
│   ├── build.js
│   └── build.js.map
├── index.html
├── package.json
├── src
│   ├── App.vue
│   ├── assets
│   │   ├── css.css
│   │   ├── icon.css
│   │   └── logo.png
│   ├── constant
│   │   └── api.js  // 配置api接口文件
│   ├── http.js // 封装fetch、post请求及http 拦截器配置文件
│   ├── index.vue
│   ├── login.vue
│   ├── main.js
│   ├── repository.vue
│   ├── router.js // 路由配置文件
│   └── store
│       ├── store.js  
│       └── types.js  // vuex types
└── webpack.config.js

技术栈

  • Vue 2.0
  • vue-router
  • vuex
  • axios
  • vue-material

登录拦截逻辑

第一步:路由拦截

首先在定义路由的时候就需要多添加一个自定义字段requireAuth,用于判断该路由的访问是否需要登录。如果用户已经登录,则顺利进入路由, 否则就进入登录页面。

const routes = [
    {
        path: '/',
        name: '/',
        component: Index
    },
    {
        path: '/repository',
        name: 'repository',
        meta: {
            requireAuth: true,  // 添加该字段,表示进入这个路由是需要登录的
        },
        component: Repository
    },
    {
        path: '/login',
        name: 'login',
        component: Login
    }
];

定义完路由后,我们主要是利用vue-router提供的钩子函数beforeEach()对路由进行判断。

router.beforeEach((to, from, next) => {
    if (to.meta.requireAuth) {  // 判断该路由是否需要登录权限
        if (store.state.token) {  // 通过vuex state获取当前的token是否存在
            next();
        }
        else {
            next({
                path: '/login',
                query: {redirect: to.fullPath}  // 将跳转的路由path作为参数,登录成功后跳转到该路由
            })
        }
    }
    else {
        next();
    }
})

每个钩子方法接收三个参数:

  • to: Route: 即将要进入的目标 路由对象
  • from: Route: 当前导航正要离开的路由
  • next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
    • next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
    • next(false): 中断当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
    • next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。

确保要调用 next 方法,否则钩子就不会被 resolved。

完整的方法见/src/router.js

其中,to.meta中是我们自定义的数据,其中就包括我们刚刚定义的requireAuth字段。通过这个字段来判断该路由是否需要登录权限。需要的话,同时当前应用不存在token,则跳转到登录页面,进行登录。登录成功后跳转到目标路由。

登录拦截到这里就结束了吗?并没有。这种方式只是简单的前端路由控制,并不能真正阻止用户访问需要登录权限的路由。还有一种情况便是:当前token失效了,但是token依然保存在本地。这时候你去访问需要登录权限的路由时,实际上应该让用户重新登录。 这时候就需要结合 http 拦截器 + 后端接口返回的http 状态码来判断。

第二步:拦截器

要想统一处理所有http请求和响应,就得用上 axios 的拦截器。通过配置http response inteceptor,当后端接口返回401 Unauthorized(未授权),让用户重新登录。

// http request 拦截器
axios.interceptors.request.use(
    config => {
        if (store.state.token) {  // 判断是否存在token,如果存在的话,则每个http header都加上token
            config.headers.Authorization = `token ${store.state.token}`;
        }
        return config;
    },
    err => {
        return Promise.reject(err);
    });

// http response 拦截器
axios.interceptors.response.use(
    response => {
        return response;
    },
    error => {
        if (error.response) {
            switch (error.response.status) {
                case 401:
                    // 返回 401 清除token信息并跳转到登录页面
                    store.commit(types.LOGOUT);
                    router.replace({
                        path: 'login',
                        query: {redirect: router.currentRoute.fullPath}
                    })
            }
        }
        return Promise.reject(error.response.data)   // 返回接口返回的错误信息
    });

完整的方法见/src/http.js.

通过上面这两步,就可以在前端实现登录拦截了。登出功能也就很简单,只需要把当前token清除,再跳转到首页即可。

源码位置 https://github.com/superman66/vue-axios-github

### 前端拦截器的概念 前端拦截器是一种设计模式,允许开发者在请求发送之前或响应接收之后执行特定逻辑。这种机制广泛应用于各种场景中,比如身份验证、日志记录以及错误处理等。 ### 实现和使用拦截器的方式 #### 在 Angular 中实现 HTTP 拦截器 Angular 提供了内置的支持来创建HTTP拦截器。通过继承`HttpInterceptor`类并实现相应的接口可以轻松地自定义网络请求的行为[^1]: ```typescript import { Injectable } from '@angular/core'; import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http'; @Injectable() export class AuthInterceptor implements HttpInterceptor { intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { const token = 'your-auth-token'; // 获取token或其他认证信息 // Clone the request to add a new header. const authReq = req.clone({ headers: req.headers.set('Authorization', `Bearer ${token}`) }); return next.handle(authReq); } } ``` 此代码片段展示了如何向所有的HTTP请求添加授权头信息。 #### 使用 Axios 在 Vue 或 React 中设置全局请求/响应拦截器 对于基于Axios库的应用程序来说,在Vue或者React项目里可以通过如下方式配置全局的请求与响应拦截器[^2]: ```javascript // 导入axios实例 const axiosInstance = require('axios').create(); // 请求拦截器 axiosInstance.interceptors.request.use( config => { // 可在此处加入Token或者其他公共参数 if (localStorage.getItem('token')) { config.headers['Authorization'] = localStorage.getItem('token'); } return config; }, error => Promise.reject(error) ); // 响应拦截器 axiosInstance.interceptors.response.use( response => response, error => { console.error(`Error occurred during API call: ${error.message}`); return Promise.reject(error); } ); ``` 这段脚本实现了对所有API调用自动附加认证令牌,并且当服务器返回异常时会打印出错消息。 #### 利用 Fetch API 和 Middleware 函数构建简单的拦截功能 如果更倾向于原生浏览器支持,则可以直接利用Fetch API配合中间件函数完成相似的任务: ```javascript function fetchWithMiddleware(url, options={}) { let middlewareQueue = []; function applyMiddleware(middlewareFn){ middlewareQueue.push(middlewareFn); } async function execute(){ let finalOptions = {...options}; for(let mw of middlewareQueue){ await mw(finalOptions); } try{ let res = await fetch(url,finalOptions); return await res.json(); }catch(e){ throw e; } } return Object.assign(execute.bind(null),{applyMiddleware}); } let myRequest = fetchWithMiddleware('/api/data',{ method:'POST', }); myRequest.applyMiddleware(async opts=>{ opts.headers={ ...opts.headers, Authorization:`Bearer ${await getAccessToken()}` }; }); myRequest().then(console.log).catch(console.error); ``` 上述例子说明了一种灵活的方式来扩展标准fetch行为而无需依赖第三方库。 ### 应用场景举例 - **身份验证**:确保每个发出到受保护资源的请求都携带有效的访问凭证。 - **加载指示符控制**:显示进度条或等待图标直到异步操作完成。 - **跨域资源共享(CORS)**:预检请求以确认目标URL是否接受来自当前源站的连接尝试。 - **缓存策略实施**:根据业务需求调整GET请求的结果存储规则。 - **性能监控**:测量前后端交互耗时以便优化用户体验。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值