主题
Git 分支与远程仓库(三)
本页对应 Git 分支与远程仓库,共 6 段视频,约 42 分钟。
学习目标
- 能够复述 JWT 验证流程,说明登录获取 token、缓存 token、请求携带 token、401 失效处理的关键环节。
- 能够使用 axios 请求拦截器统一为请求头添加 token,并处理本地无 token 或 token 解析失败时不添加 token 的场景。
- 能够使用 axios 响应拦截器统一处理 401 错误,完成提示重新登录、清除本地存储并跳转登录页。
- 能够通过响应拦截器实现数据剥离,并同步修改登录、注册、首页等页面中对应的数据读取代码。
- 能够使用 Gitee 新建远程仓库,并完成本地仓库推送、克隆和拉取操作。
知识点
需求:页面少写一层 data
为什么需要:axios 默认返回的 response 不是服务端原始响应体,而是被 axios 包装过的对象,真正业务数据在 response.data 里。页面里如果每次写 res.data.data.xxx,既啰嗦又容易漏。
怎么想:在响应拦截器的成功回调里,把 axios 包装层剥掉,直接 return response.data。这样页面拿到的 res 就是服务端响应体,原来两次 .data 变成一次。
怎么做:先看效果对比:


易错点:剥离后所有使用响应的页面都要同步改,否则会出现“数据渲染不出来/值不变”的现象。
在 commons.js 添加响应拦截器
为什么需要:401 登录失效、数据剥离都是“响应回来之后”的公共逻辑,应该统一放在公共文件,而不是每个接口都写一遍 try/catch。
怎么想:请求拦截器处理“请求发送前”,响应拦截器处理“响应回来之后”。成功响应走第一个函数,非 2xx 走第二个函数。成功函数里做数据剥离;失败函数里判断 error.response.status === 401,提示、清缓存、跳登录。
怎么做:
javascript
// 添加响应拦截器
// 统一处理token过期
// 数据剥离
axios.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么,比如: 数据剥离
// 剥离data属性,页面中少写.data属性,直接可以获取到数据
return response.data;
}, function (error) {
// console.dir(error)
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么: 比如统一处理token失效
// 统一处理token失效
if (error.response.status === 401) {
// 弹框提示用户
showToast('请重新登录')
// 删除缓存
localStorage.removeItem('token')
localStorage.removeItem('username')
// 返回登录页
setTimeout(() => {
location.href = 'login.html'
}, 1500)
}
return Promise.reject(error);
});易错点:return Promise.reject(error) 不要删。转写中特别提醒:这两个 return 是拦截器把请求/响应继续交出去的关键,删掉会导致请求或响应失效。调试 401 时,可在失败回调打印 error,展开看到 error.response.status;转写中是在 common.js 79 行附近验证到 401 的。
调整首页数据使用:移除多余 .data
为什么需要:拦截器已经返回 response.data,首页若还按旧写法取两层 data,就拿不到数据。
怎么想:原来类似 res.data.data.overview,现在应变成 res.data.overview。只删 axios 包装的那一层,服务端响应体里的 data 字段仍保留。
怎么做:
javascript
// 首页-统计数据
async function getData() {
// 调用接口(登录成功之后才可以调用)
const res = await axios({
url: '/dashboard',
// 通过axios请求拦截器统一携带
})
const overview = res.data.overview
// 渲染数据
Object.keys(overview).forEach(key => {
document.querySelector(`.${key}`).innerText = overview[key]
})
}易错点:转写调试时,改成 return response.data 后页面值不变,是因为 index.js 里还在用 res.data.data;把首页、登录、注册三处都改完才恢复。
调整注册与登录:try 中少写一层 .data
为什么需要:注册、登录的成功响应也经过同一个响应拦截器,成功时 res 已经是服务端响应体。
怎么想:成功提示用 res.message;登录缓存仍取 res.data.token、res.data.username,因为服务端响应体里仍有 data 字段。失败响应走失败回调,未被剥离,所以 catch 里仍是 error.response.data.message。
怎么做:
javascript
document.querySelector('#btn-register').addEventListener('click', async () => {
// 1. 收集并校验数据
const form = document.querySelector('.register-form')
const data = serialize(form, { empty: true, hash: true })
// console.log(data)
const { username, password } = data
console.log(username, password)
// 非空校验
if (username === '' || password === '') {
showToast('用户名和密码不能为空')
return
}
// 长度校验
if (username.length < 8 || username.length > 30 || password.length < 6 || password.length > 30) {
showToast('用户名的长度为8-30,密码的长度为6-30')
return
}
// 2. 数据提交
try {
// .post 请求方法 post,参数1:请求URL,参数2:提交的数据
const res = await axios.post('/register', { username, password })
// console.log(res)
showToast(res.message)
} catch (error) {
// console.dir(error)
showToast(error.response.data.message)
}
})javascript
document.querySelector('#btn-login').addEventListener('click', async () => {
// 1. 收集并校验数据
const form = document.querySelector('.login-form')
const data = serialize(form, { empty: true, hash: true })
console.log(data)
const { username, password } = data
// 非空判断
if (username === '' || password === '') {
showToast('用户名和密码不能为空')
return
}
// 格式判断
if (username.length < 8 || username.length > 30 || password.length < 6 || password.length > 30) {
showToast('用户名长度8-30,密码长度6-30')
return
}
// 2. 提交数据
try {
const res = await axios.post('/login', { username, password })
// console.log(res)
showToast(res.message)
// 3. 缓存响应数据
localStorage.setItem('token', res.data.token)
localStorage.setItem('username', res.data.username)
// 4. 跳转首页
// 延迟一会在跳转,让提示框显示
setTimeout(() => {
// login.html和index.html的相对关系
location.href = './index.html'
}, 1500)
} catch (error) {
// console.dir(error)
showToast(error.response.data.message)
}
})易错点:不要把 catch 里的 error.response.data.message 也改成 error.response.message,错误响应没有走成功剥离逻辑。
验证与提交
怎么做:登录成功后篡改 token 再刷新首页,观察是否提示“请重新登录”、清除缓存并跳回登录页;再正常登录,确认首页统计、注册提示、登录跳转都正常。最后提交:
bash
git add .
git commit -m"axios响应拦截器-数据剥离"易错点:数据剥离和 401 统一处理都放在 commons.js 后,页面里原来的 token 失效判断可移除,避免重复逻辑。
远程仓库是什么
远程仓库是指托管在因特网或其他网络中的项目版本库。它不是一个抽象概念,可以理解为:把本地 Git 仓库中的项目版本信息,放到一台网络上可访问的服务器上保存和管理。笔记中给出的文档地址是:Git 基础 - 远程仓库的使用。

为什么需要:如果代码只放在本地电脑里,一旦换电脑、电脑不能带走,或者同事也要参与开发,代码的传递就会很麻烦。转写稿里举了一个很具体的场景:教室里的电脑不能拿走,但晚上回家还想继续巩固代码,于是要用 U 盘拷、用网盘传;如果同事也要用,还要再把网盘链接发给他,既麻烦又不方便协作。远程仓库解决的正是“代码放在哪里、谁能拿到、多人怎么一起用”的问题。
怎么想:远程仓库类似一个公共网盘,但它不是普通网盘,而是记录项目版本库的托管位置。只要和项目有关的人需要,就可以从远程仓库获取代码;自己在公司用电脑 A、回家用电脑 B,也可以从服务器上重新拿到项目继续工作。
怎么做:把本地仓库推送到互联网中的某个托管位置,让代码在远程服务器上有一份版本库。笔记中总结的作用有两点:一是本地仓库备份,二是多人协作。这里的“多人写作”应理解为“多人协作”。
易错点:不要把远程仓库只理解成“备份盘”。它更重要的价值是支持多人协作和多设备获取代码;同时,远程仓库托管的是 Git 版本库,不是随便上传一个压缩包。
常见远程仓库怎么选
笔记列出了三类常见 Git 远程仓库:
- GitHub:面向开源及私有软件项目的托管平台,因为只支持 Git 作为唯一的版本库格式进行托管,故名 GitHub。它的特点是国内访问较慢。
- Gitee:开源中国推出的基于 Git 的代码托管服务。服务器在国内,访问迅速,课程中主要使用这个。转写稿中提到的“马云”应纠正为“码云(Gitee)”。
- GitLab:一个用于仓库管理系统的开源项目,使用 Git 作为代码管理工具,并在此基础上搭建 Web 服务。一般是公司内部部署并使用。
为什么需要了解平台:因为远程仓库必须依托具体的托管平台。不同平台的访问速度、使用场景不同,需要根据课程或团队情况选择。
怎么想:GitHub 很流行,但转写稿提醒它打开可能比较麻烦,有时会被限制,注册也不太容易,而且界面是英文的;Gitee 是国内版代码管理仓库,更适合当前课程使用;GitLab 常见于公司内部部署。
怎么做:课程中优先使用 Gitee。无论选择哪一种,只要基于 Git,用法大同小异,不必因为平台不同而认为要重新学一套完全不同的东西。
易错点:不要以为换了平台,Git 的核心概念就变了。远程仓库的托管平台不同,但 Git 管理版本库的基本思路一致;同时要注意 GitHub 国内访问较慢这一现实问题。
使用远程仓库前的准备
为什么需要:要使用远程仓库,首先要在平台上拥有自己的账号,否则无法创建和管理网络上的仓库。
怎么想:转写稿中说明,使用公共仓库前要先注册自己的账号,注册完后最好绑定邮箱。绑定邮箱是为了账号信息更完整,也方便后续使用。
怎么做:到 Gitee 官网注册账号,注册后绑定邮箱。转写稿还提到平台可能会提示修改默认分支名,但当前不用做,因为现在默认分支名就是 master;Gitee 默认也是 master 分支。如果以后确实想改,可以在“仓库首选项”里修改默认分支名。
易错点:不要一看到“修改默认分支名”的提示就立刻去改。课程当前不需要改,默认 master 即可;真正要做的是注册账号、绑定邮箱,然后准备在远程仓库上新建一个网络仓库,把本地代码推送上去。
把本地代码推到远程的思路
为什么需要:远程仓库建好后,如果里面没有项目内容,就无法实现备份和协作。因此需要把本地已有代码推送上去。
怎么想:转写稿的流程是:先有远程平台账号,再在远程仓库上新建一个网络上的仓库,然后把本地代码推送上去。这样远程服务器上就有了项目版本库,之后换设备或多人参与时,都可以围绕这个远程仓库获取代码。
怎么做:按“注册账号并绑定邮箱 → 在平台上新建远程仓库 → 将本地仓库代码推送到该远程仓库”的顺序推进。笔记没有展开具体 Git 命令,本节重点是把远程仓库的概念、作用和平台选择讲清楚。
易错点:不要跳过账号和远程仓库创建,直接谈推送;也不要把“新建远程仓库”和“本地已有仓库”混为一谈。先明确远程仓库的位置,再考虑把本地内容推上去。
先理解:远程仓库解决什么问题
为什么需要:本地代码只存在当前电脑里。转写稿里举了一个很具体的场景:教室电脑不能带走,今天代码写完了,晚上回家还想继续巩固,怎么办?用 U 盘拷、用网盘传,都行,但多人协作时就麻烦了——同事也要用,还得再发网盘链接,下载速度还可能受限制。
怎么想:远程仓库就是把本地仓库推送到互联网上的某个位置,代码托管在服务器上,项目版本库也在服务器上记录。转写稿里把它类比成“公共网盘”,但要注意它不是普通网盘,而是带版本管理能力的代码仓库。这样公司电脑 A、家里电脑 B、甚至逛街时临时想写代码,都可以从服务器拉下来继续做。
怎么做:本节选择 Gitee。转写稿里提到 GitHub 也是代码管理仓库,但英文界面、注册和访问可能麻烦;Gitee 是国内常用的代码托管平台,转写稿里口播的“getE”应理解为 Gitee,“get”应理解为 Git,“马云”应理解为“码云”。
易错点:不要把“远程仓库”理解成本地 Git 仓库;远程仓库要先有平台账号,后面才能新建网络仓库并推送本地代码。
注册 Gitee 账号
为什么需要:远程仓库要托管在平台上,账号就是你访问、创建、管理远程仓库的入口。
怎么想:先注册,再登录;没有账号,后面的绑定邮箱和仓库设置都无从谈起。
怎么做:打开 gitee,在右上角找到“注册”,按页面提示完成注册。对应笔记图片如下:

易错点:注册时用户名、邮箱、密码要填写正确;注册完成后要确认已经登录,不要停留在注册成功页就以为准备工作结束了。
绑定邮箱
为什么需要:转写稿里明确说,注册完自己的账号后“最好去绑定一下邮箱”。邮箱用于账号找回、通知和身份识别,是账号准备的重要一步。
怎么想:登录后从右上角进入账号相关设置,找到“添加绑定”,按提示新增邮箱并完成验证。
怎么做:登录之后,右上角点击“添加绑定”,根据提示新增邮箱即可。对应笔记图片如下:

易错点:只填写邮箱但没有完成验证邮件,通常不算绑定完成;验证邮件可能进垃圾箱,找不到时先检查垃圾箱。转写稿里强调“注册完账号,绑定邮箱”,所以这一步不要跳过。
设置默认分支名
为什么需要:默认分支名影响新建仓库时的初始分支。本节笔记要求把默认分支名改为 main,目的是和后续项目约定保持一致,避免本地和远程分支名不统一。
怎么想:转写稿里实际找设置时,先翻到账号管理附近,发现不是那里,最后在“仓库首选项”里找到默认分支名设置。这说明操作路径不要凭记忆,要按“个人设置/账号设置→仓库首选项”去找。转写稿还补充:Gitee 默认分支是 master,如果项目不需要 main,不改也行;但本节笔记记录的是改为 main,所以我们按笔记统一设置。转写稿里口播的“me”应理解为 main。
怎么做:找到个人设置,进入“仓库首选项”,把默认分支名改为 main。对应笔记图片如下:

易错点:不要把“仓库名”和“默认分支名”混为一谈;改的是默认分支名,不是仓库名称。分支名大小写要写准确,main 不是 master。另外,这个设置主要影响之后新建仓库的默认分支,已有仓库是否需要单独调整,以页面提示为准。
准备完成后的检查
为什么需要:确认账号、邮箱、默认分支都准备好了,后面才能顺利新建远程仓库并推送本地代码。
怎么想:按“能登录、邮箱已绑定、默认分支符合约定”三项检查。
怎么做:重新登录 Gitee,确认右上角账号状态正常;进入绑定设置确认邮箱已添加;进入仓库首选项确认默认分支名为 main。
易错点:只注册不绑定邮箱;绑定邮箱后没验证;默认分支仍停留在 master 却以为已经改成 main。转写稿最后也说明,本节先完成“什么是远程仓库”和“注册远程仓库账号”的准备,下一步才是在远程仓库上新建网络仓库,把本地代码推送上去。
先理解:远程仓库到底解决什么问题
为什么需要:本地仓库只能管住当前这台电脑。转写稿里举了一个很实际的场景:教室电脑不能带走,今天代码写完了,晚上回家还想继续改;用 U 盘拷、用网盘传,自己用还行,同事也要用时就麻烦了。远程仓库就是把本地仓库托管到互联网上的一个位置,只要和项目有关的人都能按权限使用。
怎么想:不要把远程仓库想复杂,它类似一个“公共网盘”,但它记录的是项目版本库,不只是普通文件。这样你在公司用电脑 A,回家用电脑 B,甚至逛街时临时想写代码,都可以从服务器拿代码;多人协作也有了统一入口。
怎么做:本节选择 Gitee(码云)作为远程仓库。转写稿提到 GitHub 也常用,但可能访问受限、注册相对麻烦、界面偏英文;Gitee 是国内代码管理仓库,更适合当前练习。
易错点:远程仓库不是“把文件夹压缩上传”就完事,它要和本地 Git 仓库建立对应关系;后面推送时命令要以新建仓库页面显示为准,不要照抄别人的仓库地址。
准备账号:注册、绑定邮箱、默认分支先别乱改
为什么需要:没有账号就无法在 Gitee 上创建自己的远程仓库,也无法区分仓库归属和权限。
怎么想:先注册账号,再绑定邮箱。转写稿特别说明:注册完账号后最好绑定邮箱。至于“默认分支名”,备课环境里可能叫 main,但我们现在本地默认是 master,所以不用跟着改。
怎么做:进入 Gitee 官网注册账号并绑定邮箱。若以后确实想改默认分支名,可在“账号设置”里找到“仓库首选项”进行修改;本节不要求改。因为当前本地分支默认是 master,Gitee 默认也是 master,保持一致更省事。
易错点:不要一上来就改默认分支名,否则本地和远程分支名不一致,后续推送容易多出额外操作;邮箱没绑定也可能影响账号后续使用。
新建远程仓库:点右上角“+”,填好必填项
为什么需要:远程仓库要先在服务器上创建出来,本地代码才有推送目标。
怎么想:新建仓库时,平台会让填仓库名、可见性等必填信息。这里的目标不是研究所有选项,而是先创建一个能接收本地代码的空仓库。
怎么做:登录后点击右上角的“+”,选择新建仓库;按页面要求设置必填项,完成新建。核心步骤可对照下图:

点击右上角的“+”,选择新建仓库:

设置必填项,完成新建:

易错点:仓库名和路径要看清;不要把“新建仓库”和“导入仓库”混掉;如果页面提示初始化 README 等选项,按当前课程要求选择,别随意勾选导致本地推送时还要额外处理。
推送本地代码:在项目根目录执行页面给出的命令
为什么需要:远程仓库只是空壳,本地代码还没上去。推送就是把本地提交同步到远程仓库。
怎么想:新建完成后,Gitee 页面通常会给出 2–3 行命令,告诉你如何关联远程仓库并推送。我们要做的不是背命令,而是确认当前终端位置正确,然后按页面提示执行。
怎么做:在项目根目录打开 Git Bash 或终端,依次执行页面给出的 2–3 行命令。命令内容以你新建仓库后页面显示为准,不要凭空改写。

易错点:第一,必须在项目根目录执行,不要在桌面上随便开终端;第二,命令要按页面复制,仓库地址每个人不同;第三,如果本地还没有提交,推送可能没有内容可推,应先确认本地仓库状态;第四,推送后回到 Gitee 页面刷新,确认文件已经出现。
小结:把“新建”和“推送”连成一条线
本节完成的是“新建 Gitee 远程仓库,并把本地代码推送到服务器”。流程可以记成:注册并绑定邮箱 → 右上角“+”新建仓库 → 填必填项完成创建 → 在项目根目录打开 Git Bash/终端 → 执行页面给出的 2–3 行命令 → 回远程仓库刷新验证。远程仓库的价值在于多设备、多人协作和统一托管;操作上最关键的是别改乱默认分支、别在错误目录执行、别照抄别人的仓库命令。
先理解:克隆到底解决什么问题
为什么需要: 转写稿里用了一个很直观的场景:人在教室,电脑不能带走,但晚上回家还想继续写代码;用 U 盘拷、用网盘传都行,但多人协作时再互相发网盘就很麻烦。远程仓库就像放在互联网上的“公共网盘”,代码托管在服务器上,换一台电脑可以从服务器拿下来,项目相关的人也可以围绕同一个仓库协作。本节的需求很明确:克隆(clone)——获得一份已经存在了的 Git 仓库的拷贝。
怎么想: 克隆不是“新建一个空项目”,而是把一个已经存在的远程仓库复制到本地。所以第一步不是急着敲命令,而是先确认远程仓库地址。
怎么做: 打开远程仓库首页,找到“克隆/下载”,选择 HTTPS,复制仓库地址。笔记里的核心步骤图如下:

易错点: 笔记提醒“不是 URL 地址,选择克隆/下载,找到 HTTPS,点击复制”。这里要理解为:不要随手复制浏览器地址栏里的网页 URL,而要到仓库页面的“克隆/下载”区域复制平台提供的 HTTPS 克隆地址。git clone 后面仍然需要一个仓库地址,只是这个地址要从正确位置复制。
执行克隆命令
为什么需要: 地址准备好后,必须用 Git 命令把远程仓库拉到本地,否则本地只有一个网页地址,并没有真正的项目目录。
怎么想: 命令结构很直接:git clone 加上远程仓库地址。笔记给出的形式是:
bash
git clone 远程仓库地址怎么做: 在命令行工具中进入你希望存放项目的目录,执行上面的命令。执行完成后,本地会得到一份远程仓库的拷贝。
易错点: 不要把命令写成只复制一半地址;也不要把“克隆/下载”按钮旁边的说明文字一起复制进去。地址应当来自 HTTPS 那一栏。转写稿里把 Git 说成“get”是口误,实际命令是 git。
进入克隆出来的项目目录
为什么需要: 克隆完成后,当前命令行所在目录不一定就是项目目录。后续查看分支、切换分支都要在仓库目录里执行,否则 Git 找不到仓库。
怎么想: 克隆会生成一个仓库目录,需要先进入它。笔记写的是“通过 cd 仓库目录 进入项目”。
怎么做:
bash
cd 仓库目录这里的“仓库目录”要换成你实际克隆出来的目录名。
易错点: 不要停留在上一级目录直接执行分支命令;也不要想当然认为目录名一定和远程仓库名完全一样,应以实际生成的目录名为准。本节没有给出具体仓库名,所以教程里保留“仓库目录”这个占位。
查看全部分支
为什么需要: 克隆下来后,需要知道仓库里有哪些分支。只看本地分支可能不够,因为远程分支也要确认。
怎么想: 笔记要求用 git branch -a 查看全部分支,包括本地分支和远程分支。注意笔记里写成 git branh -a 是拼写错误,正确命令是 branch。
怎么做:
bash
git branch -a执行后,远程分支通常会以类似 remotes/origin/dev 的形式显示出来。
易错点: 第一,命令拼写别少字母;第二,看到 remotes/origin/dev 不要慌,它表示远程仓库 origin 下的 dev 分支,不是让你把整串都当作切换命令。
切换远程分支
为什么需要: 查看分支是为了进入正确的开发分支。如果远程有 dev 分支,而你要在 dev 上工作,就需要切换过去。
怎么想: 笔记给了一个关键点:切换远程分支时,只需要分支名即可。例如显示的是 remotes/origin/dev,切换命令不是写一整串,而是:
bash
git checkout dev怎么做: 在仓库目录中执行 git checkout dev,然后按实际状态继续工作。
易错点: 不要把命令写成 git checkout remotes/origin/dev。笔记明确说“切换远程分支,只需要分支名即可”。另外,origin 是远程仓库的默认名称,remotes/origin/dev 只是 git branch -a 的显示形式,不是切换时要照抄的完整分支名。
把流程串起来
本节完整流程可以归纳为:先在远程仓库首页的“克隆/下载”里选择 HTTPS 并复制地址;执行 git clone 远程仓库地址;用 cd 仓库目录 进入项目;用 git branch -a 查看本地和远程全部分支;看到 remotes/origin/dev 这类远程分支后,用 git checkout dev 切换。转写稿里还提到远程仓库平台注册账号、绑定邮箱、默认分支为 master 时不必修改等内容,这些属于使用远程仓库平台的背景准备;就本节“克隆”而言,核心仍是上面的命令流程。转写稿中“马云”是口误,实际说的是码云/Gitee。本节没有给出具体终端回显和报错调试记录,因此不虚构调试输出;验证方式就是按笔记顺序执行命令,并用 git branch -a 确认分支显示,再按分支名切换。
一、先理解“拉取”和远程仓库
为什么需要: 本地代码只存在自己电脑上,换一台电脑、回家继续写、或者让同事一起协作,就不方便。转写稿里用一个很直白的场景说明:教室电脑不能带走,可以用U盘或网盘拷走;但多人协作时,最好把代码放到互联网上的一个位置,这个位置就是远程仓库。远程仓库可以理解为“公共网盘 + 版本库”,记录项目的版本,支持多设备、多人协作。转写稿中提到的“吉他”应纠正为GitHub,“马云”应指码云(Gitee);国内更推荐使用Gitee。
怎么想: 本节的核心不是重新讲本地提交,而是先解决“远程仓库能不能被访问”的问题。笔记明确写了拉取(pull)的作用:从远程仓库拉取代码并合并到本地。也就是说,拉取不是单纯“下载一份文件”,而是把远程仓库的代码取回来并合并到当前本地仓库。要让其他人访问自己的仓库,笔记特别提醒:需要把仓库设置为开源。
怎么做: 先确认自己已经有远程仓库,并且仓库里有内容;再按本节图示完成拉取相关操作。笔记中的关键步骤见下图:

易错点: 不要把“拉取”理解成只下载压缩包;笔记强调的是拉取并合并到本地。另一个易错点是:远程仓库是否能被其他人访问,和“开源设置”有关,不是把本地路径发过去就行。
二、为什么要把仓库设置为开源
为什么需要: 笔记中写得很明确:如果要让其他人访问自己的仓库,需要设置为开源。也就是说,别人要能看到、访问你的仓库,仓库的访问权限必须允许。否则即使你把地址发过去,对方也未必能正常访问。
怎么想: 这里要先区分两件事:第一,仓库里要有内容;第二,仓库要允许别人访问。笔记特别标注“仓库需要有内容才可以设置开源”,所以不要新建一个空仓库就去设置开源,否则容易找不到可勾选的选项或设置不成功。
怎么做: 进入仓库首页,点击“管理”,拉到页面底部,勾选对应选项,然后保存。笔记中的设置位置见下图:

易错点: 最常见的问题是仓库还是空的就去设置开源;其次是设置完忘记保存;还有就是以为“公开”等于“自动把地址发给别人”,其实还需要把仓库URL给协作者。
三、把仓库URL交给协作者
为什么需要: 设置开源只是让仓库具备被访问的条件,协作者还需要知道仓库在哪里。笔记给出的做法是:接下来直接将仓库的Gitee的URL地址给其他小伙伴即可。
怎么想: 远程仓库的地址就是协作入口。对方拿到URL后,才能访问仓库、继续后续的拉取等操作。这里不要发本地文件路径,也不要发自己电脑上的目录,要发Gitee仓库地址。
怎么做: 在Gitee仓库页面复制仓库URL,发给需要访问的小伙伴。对方通过这个URL访问仓库。若对方后续要拉取代码,仍要按远程仓库的拉取流程操作,关键步骤参考本节第一张图。
易错点: 不要把“仓库已开源”当成“URL已经发送”;也不要把浏览器地址栏里的无关页面地址发过去。笔记要求的是“仓库的Gitee的URL地址”。
四、转写稿补充:远程仓库使用前的准备
为什么需要: 转写稿介绍了远程仓库的使用背景:需要有自己的账号,注册后最好绑定邮箱;Gitee默认分支是master,特别说明当前不用去改默认分支名。若以后要改,可在“仓库首选项”里修改默认分支名。
怎么想: 这些准备不是拉取命令本身,但属于拉取前的前置条件:账号可用、邮箱已绑定、仓库可访问。转写稿还提到,接下来要在远程仓库上新建网络仓库,把本地代码推送上去;本节笔记聚焦“拉取”,所以具体拉取动作以笔记图片为准,不额外编造命令细节。
怎么做: 注册并登录Gitee,绑定邮箱;确认默认分支为master即可,不必按转写稿中提到的旧分支名去修改;进入目标仓库,按“管理→拉到底→勾选→保存”设置开源;复制仓库URL发给协作者。
易错点: 不要把“默认分支名”随意改掉;转写稿明确说当前不用改。也不要把账号注册、绑定邮箱、仓库开源、发送URL这几步混在一起,按顺序检查更稳妥。
课件图示








代码示例
1. commons.js —— 请求拦截器 + 响应拦截器(401 统一处理 + 数据剥离)
javascript
/* commons.js:所有页面都要引入 <script src="./commons.js"></script> */
/* 简易提示框,项目里用的是 utils 中的 showToast,这里给出等价实现,保证可直接运行 */
function showToast(msg) {
let box = document.querySelector('#toast')
if (!box) {
box = document.createElement('div')
box.id = 'toast'
box.style.cssText =
'position:fixed;left:50%;top:30%;transform:translateX(-50%);padding:10px 18px;' +
'background:rgba(0,0,0,.75);color:#fff;border-radius:6px;font-size:14px;z-index:999;'
document.body.appendChild(box)
}
box.innerText = msg
box.style.display = 'block'
clearTimeout(box.timer)
box.timer = setTimeout(() => (box.style.display = 'none'), 1500)
}
/* 0. 公共数据抽取:先取 token,取不到就是空字符串,避免后面 JSON.parse 空值报错 */
const token = localStorage.getItem('token') || ''
/* 1. 请求拦截器:每次请求发送之前都会走这里 */
axios.interceptors.request.use(
function (config) {
// 只有拿到了 token 才往请求头里加;登录页还没有 token,加了会出错
if (token) {
// 官方推荐用中括号语法
config.headers['authorization'] = token
}
return config // 必须 return,否则请求发不出去
},
function (error) {
return Promise.reject(error)
}
)
/* 2. 响应拦截器 */
axios.interceptors.response.use(
function (response) {
// 数据剥离:直接返回 response.data,页面里少写一层 .data
return response.data
},
function (error) {
// 超出 2xx 的状态码走这里,统一处理 token 失效
if (error.response && error.response.status === 401) {
showToast('请重新登录')
// 清除缓存
localStorage.removeItem('token')
localStorage.removeItem('username')
// 返回登录页(延迟一会儿,让提示框显示)
setTimeout(() => {
location.href = 'login.html'
}, 1500)
}
return Promise.reject(error) // 必须 return,错误才能继续抛给页面
}
)要点
axios.interceptors.request.use(成功回调, 失败回调),两个回调都必须return:return config把请求配置交回去,return Promise.reject(error)把错误继续抛出,删掉这两个return请求和响应都会"失效"。config.headers['authorization'] = token用中括号写法(官网推荐),不要写成config.headers.authorization。- 请求拦截器里一定要先
if (token)再添加:登录页此时还没登录,没有 token,直接添加会拿到undefined。 return response.data之后,页面里拿到的res就已经是后端返回的{ message, data },所有用到的地方必须同步少点一次.data,否则数据全是undefined。error.response在网络断开时是undefined,判断 401 前加个error.response &&更稳。
2. login.html —— 登录页(配合数据剥离后的取值)
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>登录</title>
<style>
.login-form { width: 320px; margin: 80px auto; display: flex; flex-direction: column; gap: 12px; }
.login-form input, .login-form button { height: 36px; padding: 0 10px; }
</style>
</head>
<body>
<form class="login-form">
<input type="text" name="username" placeholder="用户名(8-30位)" />
<input type="password" name="password" placeholder="密码(6-30位)" />
<button type="button" id="btn-login">登录</button>
</form>
<!-- 依赖:项目中的 axios、form-serialize,以及公共的 commons.js -->
<script src="./lib/axios.min.js"></script>
<script src="./lib/form-serialize.js"></script>
<script src="./commons.js"></script>
<script>
document.querySelector('#btn-login').addEventListener('click', async () => {
// 1. 收集并校验数据
const form = document.querySelector('.login-form')
const data = serialize(form, { empty: true, hash: true })
const { username, password } = data
// 非空判断
if (username === '' || password === '') {
showToast('用户名和密码不能为空')
return
}
// 格式判断
if (username.length < 8 || username.length > 30 || password.length < 6 || password.length > 30) {
showToast('用户名长度8-30,密码长度6-30')
return
}
// 2. 提交数据
try {
const res = await axios.post('/login', { username, password })
// 剥离后 res 就是 { message, data },直接 res.message
showToast(res.message)
// 3. 缓存响应数据
localStorage.setItem('token', res.data.token)
localStorage.setItem('username', res.data.username)
// 4. 跳转首页(延迟一会儿,让提示框显示)
setTimeout(() => {
location.href = './index.html'
}, 1500)
} catch (error) {
// 拦截器里 return Promise.reject(error) 后,这里拿到的仍是原始 error
showToast(error.response.data.message)
}
})
</script>
</body>
</html>要点
- 成功分支里
res.message、res.data.token:剥离的是 axios 最外层包装的那层data,后端自己的data字段还在,所以res.data.token保留、res.data.data.token才是多余的。 catch里的error是错误对象,不是响应数据,必须写error.response.data.message,写成error.message拿不到后端提示。- 登录成功后
localStorage.setItem('token', ...)的 key 必须和commons.js里localStorage.getItem('token')的 key 一致,否则请求拦截器永远拿不到 token。 setTimeout延迟跳转是为了让showToast提示能被看到,不加会"一闪而过"。
3. index.html —— 首页统计数据渲染(移除多余的 .data)
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>首页</title>
<style>
.card { display: flex; gap: 24px; margin: 40px; }
.card div { padding: 16px 24px; border: 1px solid #ddd; border-radius: 8px; }
</style>
</head>
<body>
<div class="card">
<div>用户总数:<span class="userTotal"></span></div>
<div>今日新增:<span class="todayNew"></span></div>
</div>
<script src="./lib/axios.min.js"></script>
<script src="./commons.js"></script>
<script>
// 首页-统计数据(登录成功之后才可以调用)
async function getData() {
const res = await axios({
url: '/dashboard'
// 通过 axios 请求拦截器统一携带 token,这里不用再写
})
// 剥离前:res.data.data.overview;剥离后:res.data.overview
const overview = res.data.overview
// 渲染数据:key 就是页面元素的类名
Object.keys(overview).forEach((key) => {
document.querySelector(`.${key}`).innerText = overview[key]
})
}
getData()
</script>
</body>
</html>要点
- 数据剥离后最容易错的一行就是这里:
res.data.data.overview→res.data.overview。改完拦截器后如果页面数字不显示,先回来检查这里有没有多写一层.data。 Object.keys(overview).forEach的key要和 HTML 里元素的class一一对应,querySelector('.userTotal')找不到元素会报Cannot set properties of null。- 首页调用接口时不需要再手动加 token,请求拦截器已经统一携带;但前提是
commons.js在index.js逻辑之前引入且localStorage里有 token。 - 三处(登录、注册、首页)要一起改:注册页
res.data.message→res.message,登录页res.data.data.message→res.message,首页res.data.data.overview→res.data.overview,漏改一处就会出现局部数据为undefined。
常见错误
1. 响应拦截器成功回调忘了 return,或 return 了整个 response
- 现象:所有接口
res变成undefined,页面数据全部不渲染;或"剥离没生效",业务里仍要写两次.data。 - 原因:
interceptors.response.use第一个回调的返回值就是后续await拿到的东西,不写 return 等于返回 undefined;写成return response则根本没剥离。 - 修法:成功回调固定
return response.data;;失败回调固定保留return Promise.reject(error);,这两个 return 都不能删。
2. 只改了拦截器,没同步改业务代码里的 .data
- 现象:首页统计数字一直停在默认值(如 15500),或报
Cannot read properties of undefined (reading 'overview')。 - 原因:拦截器剥掉了一层,业务里仍按两层写
res.data.overview、res.data.message。 - 修法:全局搜
res.data.,逐个改成res.,重点是 login.js、register.js、index.js 三处;error.response.data.message属于错误分支,不走成功回调,保持不动。
3. 请求拦截器无条件加 token
- 现象:未登录打开 login.html,控制台报
JSON.parse或Cannot read properties of null,登录请求发不出去,页面卡在登录页。 - 原因:localStorage 里没有 token 时
getItem返回 null,直接JSON.parse或直接取.token就报错。 - 修法:先取再判断——
const data = JSON.parse(localStorage.getItem('userMsg') || '{}'),再if (token) config.headers.Authorization = token,只在有 token 时才设置请求头。
4. token 读取散落各处、执行时机错乱
- 现象:控制台打印出来的
data是空对象,刚登录成功却取不到 token。 - 原因:取值语句写在 common.js 不同位置,且 common.js 与业务 js 的引入顺序不一致,执行时缓存还是空的。
- 修法:在 common.js 最外层统一取一次并转成对象,业务里直接解构;确认 common.js 在所有业务 js 之前引入。
5. 401 处理写了两份
- 现象:token 过期后刷新页面,连弹两次"请重新登录",或跳转两次、先跳走又被打断。
- 原因:拦截器里已加 401 统一处理,index.js 里旧的 try/catch 判断 401 没删。
- 修法:删掉业务层的 401 分支、手动清缓存和跳转代码,只留拦截器一份;判断写成
error.response.status === 401(不是error.status,也不是error.response.data.status)。
6. 推送显示成功,远程仓库首页还是空的
- 现象:本地
git push无报错,刷新 gitee 仓库页面没有文件,别人 clone 下来是空目录。 - 原因:没
git add .+git commit就 push;或本地分支是master、远程默认分支却是main;或推的分支不是默认分支。 - 修法:先
git status确认已提交,再git push -u origin 当前分支名,用git branch -a核对本地与远程分支名,必要时在仓库设置里改默认分支。
7. clone 时复制错地址,或仓库没开源
- 现象:
git clone报仓库不存在 / 403;别人打开链接看不到代码。 - 原因:复制的是浏览器地址栏 URL,而不是"克隆/下载"里的 HTTPS 地址;仓库未设为开源。
- 修法:只复制 HTTPS 克隆地址;在仓库"管理"里勾选开源选项(仓库需先有内容)。
练习
练习 1|请求拦截器 + 未登录不报错 在 common.js 中写请求拦截器:从缓存取用户信息,有 token 才写入请求头,无 token 直接放行。验收:清空缓存后打开 login.html,控制台无报错,登录请求能正常发出并在 Network 的请求头中看不到 Authorization。
练习 2|数据剥离后修复三处 给响应拦截器成功回调加数据剥离,然后同步修改 login.js、register.js、index.js 的数据使用逻辑。验收:登录、注册提示正常,首页统计数字正常渲染,全局搜索 res.data. 无残留。
练习 3|模拟 401 统一处理 登录后手动篡改 localStorage 中的 token 再刷新首页,观察行为。验收:只弹一次"请重新登录",1.5 秒后跳回登录页,缓存被清空;index.js 中不再有 401 判断代码。
练习 4|新建仓库并推送 在 gitee 新建仓库,把本地项目推上去,再在另一个目录 git clone 下来运行。验收:远程仓库首页能看到文件列表,克隆下来的项目能正常运行,git log 中有完整提交记录。
练习 5|分支核对 在克隆下来的项目中执行 git branch -a,找到远程的 dev 分支并切换过去。验收:能说明本地分支与 remotes/origin/xxx 的区别,切换命令只写分支名即可成功。
原视频对照
| # | 视频 | 时长 |
|---|---|---|
| 1 | 总结-JWT验证过程 | 02:16 |
| 2 | 案例-增加请求拦截器 | 09:49 |
| 3 | 案例-请求拦截器完成 | 09:14 |
| 4 | 案例-添加响应拦截器 | 08:20 |
| 5 | 案例-响应拦截器-数据剥离 | 07:22 |
| 6 | 远程仓库介绍 | 05:16 |
小结
- 拦截器回调里的 return 就是"交给下游的东西",成功回调不 return 或 return 错对象,全站接口一起挂,排查时先看这一行。
- 数据剥离是一次"契约变更",改拦截器的同时必须同步改所有调用点,否则症状是"接口有返回但页面不更新"。
- 请求拦截器加 token 必须带存在性判断,未登录态是必测场景,不能只在登录后的页面上验证。
- 缓存读取统一收口到 common.js 最外层,散落读取 + 脚本加载顺序是"取到空对象"类问题的主要来源。
- 公共逻辑一旦上移到拦截器,业务层同类代码必须删除,否则会出现重复提示、重复跳转这类"看起来像 bug 的实现问题"。
- 401 的判断路径是
error.response.status,错误分支拿到的是 error 而不是 response,这点和成功分支完全对称。 - 远程仓库的价值是备份 + 协作,push 前先
git status看有没有未提交内容,分支名不一致是"推了但看不到"的第一嫌疑。 - 遇到"代码没生效"先别改逻辑,按三步定位:拦截器有没有执行(打日志)→ 返回值对不对(打印结构)→ 调用点有没有跟着改。