2024年前端最全如何架构一个中后台项目的前端部分(webpack + 接口配置篇),前端面试常问的算法题

总结

面试前要精心做好准备,简历上写的知识点和原理都需要准备好,项目上多想想难点和亮点,这是面试时能和别人不一样的地方。

还有就是表现出自己的谦虚好学,以及对于未来持续进阶的规划,企业招人更偏爱稳定的人。

万事开头难,但是程序员这一条路坚持几年后发展空间还是非常大的,一切重在坚持。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

前端面试题汇总

JavaScript

前端资料汇总

‘/LOCAL_URL’: {

target: proxyTarget,

changeOrigin: true,

pathRewrite: {

‘^/LOCAL_URL’: ‘’

}

}

},

}

}

复制代码上方我们除了配置了本地启动的 host 和 端口外,还进行了 proxy 的配置。当我们的接口匹配到 /LOCAL_URL(在接口封装篇会讲解) 字段时,就会将请求服务转发到其 target 配置下,同时重写路由地址,将假地址前缀删除,实现接口的转发。

特殊配置

最后,在实现了基本配置、额外配置、本地配置后,我们再来看下特殊配置。特殊配置也就是在特殊场景下进行特殊处理的配置,比如我在架构这一中后台项目时,一套代码会运行在不同站点上(也就是发布到不同服务器上),不同站点有些配置也是不一样的,比如权限、页面展示、接口调用地址等都可能不尽相同。

那么如何在发布前不手动去修改对应站点的配置,而是以一种自动化的方式来解决呢?我们可以跑不同的 npm 命令来实现:

/* package.json */

{

“scripts”: {

“local”: “vue-cli-service serve”,

“a_dev_build”: “vue-cli-service build --site a --env development”,

“b_dev_build”: “vue-cli-service build --site b --env development”,

“a_build”: “vue-cli-service build --site a --env production”,

“b_build”: “vue-cli-service build --site b --env production”,

},

}

复制代码比如说,当我们要发布 a 站点到预发环境时,我们只需要在发布前(可以交给发布系统运行)运行 npm run a_dev_build 命令,然后 vue.config.js 中去读取相应配置,注入全局环境变量即可:

const site = process.argv.slice(4, 5)[0] || ‘a’ // 当前运行站点

const env = process.argv.slice(6, 7)[0] || ‘development’ // 当前运行前端环境

const local = process.env.npm_lifecycle_event === ‘local’ ? ‘on’ : ‘off’ // 是否调用本地接口

module.exports = {

chainWebpack: config => {

// 注入环境变量

config.plugin(‘define’)

.tap(args => {

let name = ‘process.env’

// 使用 merge 保证原始值不变

args[0][name] = merge(args[0][name], {

SITE: JSON.stringify(site),

LOCAL: JSON.stringify(local),

CLIENT_ENV: JSON.stringify(env)

})

return args

})

}

}

复制代码最后在前端环境中再去根据不同的站点、不同的环境运行不同的代码(包括接口、界面显示等)即可。当然你也可以换其他方式实现相同的功能,比如使用 cross-env 或者 mode 这样的工具或参数。

接口封装

前端的动态数据交互离不开服务端提供的接口,在一个前后端分离的中后台项目中,接口的请求和响应是必不可少的。

那么在架构一个中后台系统的时候,我们如何有效的管理和封装接口,提高项目接口调用的统一性、可维护性,以及在后端接口还没有开发完成,在仅有契约的基础上我们如何有效的模拟接口的调用呢?

接下来便会对以上问题提供个人解决方案供大家参考。

  1. 不封装存在的问题

首先谈谈接口封装,因为我们使用的请求库是 axios,所以接下来的示例都以 axios 来举例。

那么在没有封装接口的项目中,你可能随处可见接口的直接调用方法,比如像这样:

axios.post(’/user’, {

firstName: ‘zhang’,

lastName: ‘san’

})

.then(function (response) {

console.log(response);

});

axios.get(’/user?ID=12345’)

.then(function (response) {

// handle success

console.log(response);

});

复制代码这样的写法会存在一些缺点,主要有以下几点:

接口 url 没有统一管理,散落在项目的各个地方

如果需要在接口调用成功和失败时做一些处理,需要在每个地方进行添加

特殊请求头以及取消请求方法需要单独进行编写

  1. 修改默认配置

既然会存在上述问题,那么我们就需要去解决。在之前介绍的项目目录结构中,我们会发现有 services 文件夹,这就是用来存放封装的接口和调用的方法的。

在接口封装过程中,首先我们需要修改 axios 的默认配置,如下:

import axios from ‘axios’

// 修改默认配置

axios.defaults.headers.post[‘Content-Type’] = ‘application/json’

axios.defaults.headers.get[‘Content-Type’] = ‘application/json’

axios.defaults.withCredentials = true // 表示是否跨域访问请求

复制代码可以把你常用的请求头的 Content-Type 设置为默认值,同时开启跨域功能。

3. 设置拦截器

接下来需要编写下请求和响应的拦截器,来对请求和响应进行适时拦截,比如再调用重复接口时,取消上一次未完成的相同请求:

const CancelToken = axios.CancelToken

const httpPending = [] // 用于存储每个ajax请求的取消函数和ajax标识

// 取消请求方法

const cancelHttp = (name, config = {}) => {

httpPending.forEach((e, i) => {

if (e.n === name || e.n === config.xhrName) { // 当前请求在数组中存在时执行函数体

e.f() // 执行取消操作

httpPending.splice(i, 1) // 把这条记录从数组中移除

}

})

}

// 请求拦截器

axios.interceptors.request.use(config => {

// 取消上一次未完成的相同请求,注意项目中是否存在风险

cancelHttp(null, config)

config.cancelToken = new CancelToken(c => {

if (config.xhrName) {

httpPending.push({

n: config.xhrName,

u: ${config.url}&${config.method},

f: c

})

}

})

return config

}, error => Promise.reject(error))

// 响应拦截器

axios.interceptors.response.use(res => {

cancelHttp(null, res.config) // 响应成功把已经完成的请求从 httpPending 中移除

checkStatus(res) // 校验响应状态

const response = res.data

return Promise.resolve(response)

}, error => Promise.reject(error))

复制代码上述两个拦截器主要做了重复请求的拦截功能,在请求头中将请求的取消请求方法和标识符号插入数组中,当然之前需要去数组中查找是否存在相同请求,存在则提前取消请求,最后在响应时把已经完成的请求信息从数组中移除。

这里为了避免风险,我们需要在接口调用的地方手动传入一个 xhrName 标识这个请求名称才会取消重复调用该接口的请求,其余接口不做处理。

同时我们也将 cancelHttp 暴露给全局,满足手动取消请求的需要:

Vue.prototype.$cancelHttp = cancelHttp

复制代码4. 暴露调用方法

当我们完成了针对 axios 的一些设置后,我们最终的目的是使用它来请求和处理接口,那么是时候对请求调用的方法进行封装和暴露了:

import uriConfig from ‘@/config/apiUriConf’

import GLOBAL from ‘@/config/global’ // 全局变量

export default class Http {

static async request(method, url, opts, type) {

// 开启本地 mock 的话,不使用接口域名

let hostName = GLOBAL.mockLocal ? ‘’ : uriConfig.apiUrl

// 特殊接口域名

let otherName = GLOBAL.mockLocal ? ‘’ : (uriConfig[type] || ‘’)

// type 存在则使用对应的接口,否则使用通用接口

let uri = type ? ${otherName}${url} : ${hostName}${url}

// 接口别名、请求方式及url

let params = {

xhrName: (opts && opts.name) || ‘’,

method,

url: uri,

}

// 请求数据

params.data = opts.body || {}

// 设置特殊请求头

if (opts.type === ‘formData’) {

params.headers = {

‘Content-Type’: ‘application/x-www-form-urlencoded’

}

}

return axios(params)

}

static get(url, opts) {

return this.request(‘GET’, url, opts)

}

static put(url, opts) {

return this.request(‘PUT’, url, opts)

}

static post(url, opts) {

return this.request(‘POST’, url, opts)

}

static patch(url, opts) {

return this.request(‘PATCH’, url, opts)

}

static delete(url, opts) {

return this.request(‘DELETE’, url, opts)

}

}

复制代码上方我们将封装了一个 Http 类,其中包含了 get、post 等请求方法,这些请求方法内部都会去调用 request 方法,该方法会通过传入的不同参数执行原始 axios 的请求调用,返回一个 Promise。

5. 引用调用方法

那么哪里去使用这个 Http 类呢,我们可以在 services 文件夹中再建立其他接口管理文件,比如 user.js,用于存放用户相关的接口:

// user.js

import Http from ‘./http’

// 获取用户信息

文末

逆水行舟不进则退,所以大家要有危机意识。

同样是干到35岁,普通人写业务代码划水,榜样们深度学习拓宽视野晋升管理。

这也是为什么大家都说35岁是程序员的门槛,很多人迈不过去,其实各行各业都是这样都会有个坎,公司永远都缺的高级人才,只用这样才能在大风大浪过后,依然闪耀不被公司淘汰不被社会淘汰。

为了帮助大家更好温习重点知识、更高效的准备面试,特别整理了《前端工程师核心知识笔记》电子稿文件。

内容包括html,css,JavaScript,ES6,计算机网络,浏览器,工程化,模块化,Node.js,框架,数据结构,性能优化,项目等等。

269页《前端大厂面试宝典》

包含了腾讯、字节跳动、小米、阿里、滴滴、美团、58、拼多多、360、新浪、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

前端面试题汇总

  • 26
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值