> 技术文档 > 【AJAX项目】黑马头条——数据管理平台

【AJAX项目】黑马头条——数据管理平台

 

目录

一、 项目准备

二、 验证码登录

真正的验证码登录原理:

三、 token的介绍

概念:访问权限的令牌,本质上是一串字符串

创建:正确登录后,由后端签发并返回

作用:判断是否有登录状态等,控制访问权限

四、个人信息设置和axios请求拦截器

五、axios响应拦截器

优化-axios响应结果

六、发布文章 - 富文本编辑器 (wangEditor插件)

七、发布文章-频道列表

八、发布文章 - 封面设置

九、发布文章 - 收集并保存

十、内容管理 - 文章列表展示

十一、内容管理 - 筛选功能

十二、内容管理 - 分页功能

十三、内容管理 - 删除功能

十四、内容管理-编辑文章-回显

十五、编辑文字-保存

总结不易~ 本章节对我有很大收获,希望对你也是!!!


本节素材已上传至Gitee:ajax_study: 这是ajax、Node.j学习的仓库 - Gitee.comhttps://gitee.com/liu-yihao-hhh/ajax_study/tree/master/%E9%A1%B9%E7%9B%AE-%E6%95%B0%E6%8D%AE%E7%AE%A1%E7%90%86

一、 项目准备

技术:

  • 基于BootStrap 搭建网站标签和样式
  • 集成wangEditor插件实现富文本编辑器
  • 使用原生JS完成增删改查等业务
  • 基于axios与黑马头条线上接口交互
  • 使用axios拦截器进行权限判断

包含html, css, js, 静态图片, 第三方插件

目录管理:

  • assets: 资源文件夹(图片、字体等)
  • lib: 资料文件夹(第三方插件,例如:form-serialize)
  • page: 页面文件夹
  • utils: 实用程序文件夹(工具插件)

二、 验证码登录

  • 目标:完成验证码登录,后端设置验证码默认为246810
  • 原因:因为短信接口不是免费的,防止攻击者恶意盗刷

步骤:

  • 再utils/request.js配置axios请求基地址
  • 作用:提取公共前缀地址,配置后axios请求时都会baseURL + url 防止项目太大,基地址发生变化会导致所有页面请求数据地址全要变动
  • 收集手机号和验证码数据
  • 基于axios调用验证码登录接口
  • 使用BootStrap的Alert警告框反馈结果给用户

收集表单数据,上传到服务器,然后通过try……catch……来判断是否请求成功,通过myAlert函数来进行登录效果弹窗 

// 1.2 收集手机号和验证码数据document.querySelector(\'.btn\').addEventListener(\'click\', async () => { const form = document.querySelector(\'.login-form\') const data = serialize(form, { hash: true, empty: true }) console.log(data) try { // 1.3 基于 axios 调用验证码登录接口 const response = await axios.post(\'/v1_0/authorizations\', data) const result = response.data console.log(\'#\', result) myAlert(true, \'登录成功\') } catch (error) { myAlert(false, error.response.data.message) }})

alert检查验证码和手机号是否正确的弹窗

// 弹窗插件// 需要先准备 alert 样式相关的 DOM/** * BS 的 Alert 警告框函数,2秒后自动消失 * @param {*} isSuccess 成功 true,失败 false * @param {*} msg 提示消息 */function myAlert(isSuccess, msg) { const myAlert = document.querySelector(\'.alert\') myAlert.classList.add(isSuccess ? \'alert-success\' : \'alert-danger\') myAlert.innerHTML = msg myAlert.classList.add(\'show\') setTimeout(() => { myAlert.classList.remove(isSuccess ? \'alert-success\' : \'alert-danger\') myAlert.innerHTML = \'\' myAlert.classList.remove(\'show\') }, 2000)}

真正的验证码登录原理:

  1. 用户操作触发:用户在登录界面输入手机号码,主动点击 “发送验证码” 按钮,发起获取验证码流程,这是整个登录校验的起始交互 。
  2. 调用发送接口:系统携带用户输入的手机号码,调用专门用于发送短信验证码的服务器接口,传递手机号码参数,请求服务端执行发送验证码前置操作 。
  3. 服务端生成校验码:服务器接收到请求后,为该手机号码生成唯一的验证码,同时记录验证码生成时间,将这些信息存储在服务器,用于后续验证匹配 。
  4. 调用运营商通道:服务器携带手机号码,调用运营商(电信、移动、联通 )提供的短信发送接口,借助运营商网络能力传递验证码下发指令 。
  5. 基站下发短信:运营商通过基站,以无连接的短信方式,将包含验证码的信息发送到指定手机号码对应的终端设备 。
  6. 反馈发送状态:运营商将短信发送结果(成功 / 失败等 )返回给服务器,告知验证码是否已成功进入下发流程 。
  7. 返回前端结果:服务器把验证码发送成功的状态反馈给前端页面,让用户知晓验证码已尝试下发 。
  8. 用户填写验证码:用户查看手机收到的短信,获取验证码内容后,手动填写到登录页面的验证码输入框,完成信息回填 。
  9. 发起登录验证:用户点击 “登录”,系统携带手机号码和填写的验证码,调用服务器的验证码登录验证接口,提交验证请求 。
  10. 服务端校验逻辑:服务器接收请求后,拿收到的手机号码、验证码,与第 3 步生成存储的验证码记录(含号码、验证码、生成时间 )比对,校验验证码是否正确、是否在有效期(基于生成时间判断 ),然后返回登录成功或失败结果 。

三、 token的介绍

概念:访问权限的令牌,本质上是一串字符串

创建:正确登录后,由后端签发并返回

eyJzX0BAiOiJkV1QLChbc6IojT2UziIN19.eyJpc3MiOiJodHRwczovL3dL5dy5pdmNhc3RQVyJ2F1iOiJ3iCVjIof0wIY2THNnGEYJN5COUZDYLT110WOdGQYZ2ZIzUYJtxW11amR10j0wWZMMNJet2UY5DGYz3L7G4MKcAT2M2K62KtgNDcz21YtwFUj0xJ0nKwJKxLcJleHAiOjE20DE20YOT9FJkvIGauMp1Z6w.co0eqX4SCR6v8VbouuPzYVw84

作用:判断是否有登录状态等,控制访问权限

注意:前端只能判断token有无,而后端才能判断token的有效性

token的使用

目标:只有登录状态,才可以访问内容页面

步骤:

  1. 在 utils/auth.js 中判断无 token 令牌字符串,则强制跳转到登录页 (手动修改地址栏测试)
  2. 在登录成功后,保存 token 令牌字符串到本地,再跳转到首页 (手动修改地址栏测试)

观察一下没有进行登录,也就没用本地存储的token,会被踢回登录页面

// 1.1 判断无 token 令牌字符串,则强制跳转到登录页const token = localStorage.getItem(\'token\')if(!token) { localStorage.href = \'../login/index.html\'}

登录成功后,将当前服务器返回的token进行本地存储

// 1.2 收集手机号和验证码数据document.querySelector(\'.btn\').addEventListener(\'click\', async () => { const form = document.querySelector(\'.login-form\') const data = serialize(form, { hash: true, empty: true }) console.log(data) try { // 1.3 基于 axios 调用验证码登录接口 const response = await axios.post(\'/v1_0/authorizations\', data) const result = response.data console.log(\'#\', result) myAlert(true, \'登录成功\') // 登录成功后 保存token令牌到本地 并跳转到列表表表面 localStorage.setItem(\'token\', result.data.token) console.log(result.data) setTimeout(() => { // 延迟跳转 让alert警告框停留一会 location.href = \'../content/index.html\' }, 1500) } catch (error) { myAlert(false, error.response.data.message) }})

四、个人信息设置和axios请求拦截器

axios请求拦截器:发起请求之前,触发的配置函数,对请求参数进行额外配置

axios.interceptors.request.use(function (config) { const token = localStorage.getItem(\'token\'); token && (config.headers.Authorization = `Bearer ${token}`); // 在发送请求之前做些什么 return config;}, function (error) { // 对请求错误做些什么 return Promise.reject(error);});
  • 身份验证:如上述例子,在每次请求发送到服务器前,检查并添加用户的身份验证 token,确保只有已登录且拥有合法权限的用户请求才能被服务器处理 。
  • 请求参数统一处理:可以在拦截器中对所有请求的参数进行统一的格式化、添加公共参数(如时间戳、设备标识等) 等操作。
  • 请求头统一设置:除了设置身份验证信息,还可以统一设置Content-TypeAccept等请求头字段,确保所有请求的格式符合服务器要求。

在request.js文件中设置axios请求拦截器

// 目标2:设置个人信息// 2.1 在utils/request.js 设置请求拦截器 同意携带token// 2.2 请求个人信息并设置到页面// utils/request.jsaxios.interceptors.request.use(function (config) { // 统一携带 token const token = localStorage.getItem(\'token\') if (token) { config.headers.Authorization = `Bearer ${token}` } return config}, function (error) { return Promise.reject(error)})

在每次 HTTP 请求发送前自动添加身份验证令牌(Token),确保后端能够识别请求者的身份。这样,所有需要身份验证的 API 请求都会自动携带 Token,无需在每个请求中手动设置。

五、axios响应拦截器

axios响应拦截器:作用是在请求返回结果(进入 then/catch 前)统一处理响应,让你不用在每个请求里重复写逻辑。

axios.interceptors.response.use( function (response) { // 1. 响应成功(状态码 2xx 范围)时触发 return response; }, function (error) { // 2. 响应失败(状态码非 2xx,或请求报错)时触发 return Promise.reject(error); });

Axios 响应拦截器会在所有请求完成后自动触发,无论请求成功(状态码 2xx)还是失败(状态码非 2xx 或网络错误)。它的本质是一个中间层,在响应数据到达你的业务代码(.then() 或 .catch())之前执行。

无论哪一个页面发生响应401请求错误,都会在这段代码里进行拦截,并且跳转到登录页面。 

// 响应拦截器axios.interceptors.response.use( function (response) { // 1. 响应成功(状态码 2xx 范围)时触发 return response; }, function (error) { // 2. 响应失败(状态码非 2xx,或请求报错)时触发 console.dir(error) if (error?.response?.status === 401) { alert(\'身份验证失败,请重新登陆\') localStorage.clear() location.href = \'../login/index.html\' } return Promise.reject(error); });

当我修改了token值后,后端服务器发现token值对不上了,就被axios响应拦截了。 

打个比方:

  • 请求拦截器是 “快递员”,负责把包裹(请求)送到仓库(后端)。
  • 后端是 “仓库安检员”,检查包裹里的 token(身份)是否合法。
  • 响应拦截器是 “你”,收到仓库(后端)退回的 “身份不符” 包裹(401 响应),然后决定怎么处理(提示重新登录)。

总结:

  • 响应回到then和catch之前,触发的拦截函数,对响应结果统一处理时axios响应拦截器
  • axios响应拦截器状态为2xx触发成功回调,其他则触发失败回调函数

优化-axios响应结果

axios直接接收服务器返回的响应结果 就是return response.data,返回后,其他文件得到服务器返回的数据都可以少一层.data操作

// 响应拦截器axios.interceptors.response.use( function (response) { // 1. 响应成功(状态码 2xx 范围)时触发 const result = response.data return result }, function (error) { // 2. 响应失败(状态码非 2xx,或请求报错)时触发 console.dir(error) if (error?.response?.status === 401) { alert(\'身份验证失败,请重新登陆\') localStorage.clear() location.href = \'../login/index.html\' } return Promise.reject(error); });

这是因为 Axios 响应拦截器的 “全局预处理” 特性,能在响应返回业务代码前,统一 “剥掉” response.data 这一层。

六、发布文章 - 富文本编辑器 (wangEditor插件)

 

富文本:带样式,多格式的文本,在前端一般使用标签配合内联样式实现

就是跟elementpuls组件库一样

 

editor.js文件 

// 富文本编辑器// 创建编辑器函数,创建工具栏函数const { createEditor, createToolbar } = window.wangEditor// 编辑器配置对象const editorConfig = { // 占位提示文字 placeholder: \'发布文章内容...\', // 编辑器变化时回调函数 onChange(editor) { // 获取富文本内容 const html = editor.getHtml() // 也可以同步到