前端地基四件套:HTTP、浏览器、跨域与Git实战指南
老板在旁边看着接口联调突然报了一堆跨域错误浏览器控制台红成一片Git 提交又卡在 SSH 认证上——这种场景但凡写过前端的人都懂。第 1115 天这段学习内容正好是前端入门之后最容易卡壳的“地基”阶段HTTP、浏览器、跨域、Git。这四块东西不是孤立的知识点而是每天写代码都在打交道的基础设施。我见过不少同事业务代码写得很溜一被问到“HTTP 连接复用是怎么工作的”“为什么接口报 403”“Git 分支冲突怎么处理”就支支吾吾包括我自己早期也踩过不少坑。把这四样吃透前端面试题里至少三分之一能稳稳拿下日常开发效率也会明显上一个台阶。这篇总结是我把这 5 天的学习内容串起来之后再结合自己实际项目里的排错经验整理出来的适合正在系统学习前端、准备面试或者已经开始写业务但基础还不牢的朋友参考。1. HTTP 核心知识点实战拆解1.1 先理清 HTTP 的定位浏览器和服务器之间的“点餐流程”HTTPHyperText Transfer Protocol超文本传输协议是浏览器和服务器之间交流的共同语言。你不需要关心底层网络怎么传输只要按照 HTTP 的格式把请求发出去服务器照着同样格式处理并返回浏览器再解析渲染成页面整套流程就完成了。用一个生活场景类比去餐厅点餐。你举手叫服务员发起请求服务员记录你要什么菜请求头带上你的意图后厨做菜服务器处理服务员把菜端上来响应返回你吃菜浏览器解析渲染。HTTP 就是这套沟通规则什么时候举手、菜单上怎么写、服务员怎么端菜、哪些菜要额外处理状态码等等。这里有一个新手容易忽略的关键特性HTTP 是无状态的。意思是HTTP 协议本身不记得你上一次和服务器的交互每个请求之间互相独立。那网站为什么能记住你登录没登录靠的是 Cookie、Session、Token 这类额外机制。理解这一点后面看跨域、看缓存、看鉴权都会顺畅很多。1.2 报文结构请求行、请求头、请求体一个都不能少一个完整的 HTTP 请求包含三部分请求行、请求头、请求体。响应也一样包含状态行、响应头、响应体。拿一个最常见的 POST 请求举例抓包看到的东西大致长这样POST /api/login HTTP/1.1 Host: example.com Content-Type: application/json User-Agent: Mozilla/5.0 Authorization: Bearer xxxxx {username: admin, password: 123456}第一行POST /api/login HTTP/1.1是请求行明确了方法、路径和协议版本。中间是各种请求头每个头都有专门用途。空行之后是请求体也就是真正提交给服务器的数据。请求头里最值得花时间研究的是Content-Type它告诉服务器“我这个请求体的数据是什么格式”。实际开发中三个值最常用application/jsonJSON 字符串前后端分离项目的主流格式。application/x-www-form-urlencoded表单编码格式keyvaluekey2value2传统表单提交默认使用。multipart/form-data文件上传专用能携带二进制数据。我踩过最经典的坑就是后端接口文档写的是接收 JSON但我用 fetch 时传了Content-Type: application/x-www-form-urlencoded结果后端框架比如 Spring在解析请求体时拿到的是空对象排查了整整一个小时。所以联调时第一步永远先看请求头里的 Content-Type 和后端期望的是否一致。1.3 请求方法与状态码面试和排错都靠它们请求方法里前端日常接触最多的就是 GET 和 POST。但面试官喜欢追问的是“GET 和 POST 的区别”很多人的回答停留在“GET 参数在 URL 上POST 参数在 body 里POST 更安全”其实并不全面。更严谨的说法是GET 和 POST 的主要区别在于语义和幂等性。GET 用于获取资源是幂等的同一个请求执行多少次结果都一样所以浏览器可以缓存它、预加载它POST 用于提交数据不是幂等的重复提交可能会创建多条记录。另外实际工程里 GET 请求的参数确实会拼在 URL 上而 URL 长度有限制不同浏览器、服务器限制不同所以不适合传大量数据POST 的请求体体积限制要宽松得多。至于安全性HTTPS 加密之后两者都一样安全裸 HTTP 都不安全这个认知面试时最好纠正过来。状态码是排错的核心线索前端最常用到的可以整理成一张速查表状态码含义前端排查方向200请求成功正常201创建成功通常用于 POST 写入接口204无内容返回删除类接口常见301 / 302永久重定向 / 临时重定向地址是否变更为新域名304协商缓存未修改命中缓存不是错误400请求参数有误检查请求体格式、参数名、Content-Type401未认证Token 缺失、过期需要重新登录403无权限登录了但没权限或跨域拦截404路径不存在检查接口地址拼写500服务器内部错误交给后端看日志前端先抓请求参数502 / 503网关错误 / 服务不可用后端服务挂了或部署中等一等再试排错思路也很直接400 和 401、403 这种多半是前端请求本身的问题先自己检查500 以上是后端的问题但前端要提供完整请求信息给对方包括 URL、请求头、请求体、当时的浏览器版本而不是干巴巴甩一句“接口报错了”。1.4 HTTP 连接复用从每次新建连接到 keep-alive 和 HTTP/2很多老工程师提到性能优化必聊连接复用这是有道理的。最早期的 HTTP/1.0 时代每发一个请求都要经历一次完整的 TCP 三次握手请求多了性能和资源消耗都扛不住。HTTP/1.1 引入了一个关键机制keep-alive也就是默认开启连接复用。同一个域名下浏览器和服务器建立一次 TCP 连接后可以连续发送多个请求不用反复握手。这就是热词“HTTP 连接复用”的实际含义。你打开 Chrome DevTools 的 Network 面板点到某个请求在 Headers 里能看到Connection: keep-alive说明这次请求复用了之前的连接。到了 HTTP/2更进一步一个连接上可以同时并发多个请求叫多路复用彻底解决了 HTTP/1.1 时代“队头阻塞”的问题前一个请求慢后面请求只能排队等。对前端而言理解连接复用的现实意义是不要为了“减少请求数”而把大量请求强行合并在一个接口里尤其在 HTTP/2 环境下多个小请求的代价比想象中低但要注意静态资源域名拆分在 HTTP/2 下已经意义不大了反而可能因为失去连接复用而变慢。这个认知能帮你避免用过时的方案优化现在的项目。1.5 前端发请求的三种方式XHR、fetch 与 axios搞明白协议层之后再看代码层面。前端发请求基本就是三条路原生 XMLHttpRequest老古董但面试会问、fetch浏览器原生支持、axios基于 XHR 的封装库目前最主流。三者的关系可以这样理解XHR 是最底层的浏览器 API能力有但用起来繁琐fetch 是新一代原生 API写法 Promise 化更优雅直接在浏览器里就能用而不用引第三方库axios 是在 XHR 之上的封装自动处理 JSON、拦截器、取消请求、超时等代码更顺手。实际开发里我比较推荐 axios但 fetch 也建议掌握因为很多轻量场景根本不需要引一个库。使用 fetch 有几个坑是文档不会提醒你的默认不带 Cookie跨域请求要带 Cookie 必须手动加credentials: include。不主动抛超时错误需要自己通过 AbortController 控制。收到 HTTP 错误状态码比如 404、500时不会走 reject要手动判断response.ok。这些细节在面试中也很值钱因为面试官问“你知道 fetch 和 axios 有什么区别吗”想听到的就是这类实战差异而不是“axios 支持拦截器”这种一句话答案。2. 浏览器工作机制与前端面试高频考点2.1 从输入 URL 到页面显示这 6 步是必备题“浏览器从输入 URL 到页面展示发生了什么”是前端面试题中的常青树。完整流程可以拆成六步DNS 解析把域名解析成 IP 地址。浏览器会依次查浏览器缓存、系统 hosts、本地 DNS 服务器最后才去上级 DNS 查。建立 TCP 连接通过三次握手确认双方都能收发数据。发送 HTTP 请求把请求行、请求头、请求体发给服务器。服务器处理并返回响应后端处理完业务逻辑后返回 HTML、CSS、JS、数据等。浏览器解析和渲染解析 HTML 生成 DOM 树解析 CSS 生成 CSSOM 树合在一起生成渲染树然后布局、绘制。连接断开或复用HTTP/1.1 之后默认 keep-alive很多请求不会被立刻断开。其中第三步和第六步最容易引申出深聊点比如“HTTPS 和 HTTP 有什么区别”“为什么会有连接复用”“DNS 缓存失效怎么办”。我建议把这几步当成一条线反复多讲几遍讲到自己能不看笔记复述出来的程度面试基本就稳了。2.2 渲染流程DOM、CSSOM、渲染树、回流与重绘渲染这一步展开讲知识点密度非常高。浏览器拿到 HTML 之后会先把标签解析成一棵 DOM 树同时解析 CSS 生成 CSSOM 树然后两棵树合并成渲染树Render Tree只包含可见元素接着进入布局阶段计算每个节点在视口内的位置和尺寸最后才是绘制阶段把像素画到屏幕上。这里面前端性能优化最关注的是“回流”和“重绘”这对概念回流重排Reflow当元素的尺寸、位置发生变化影响到了布局时浏览器需要重新计算几何属性。比如修改元素的width、height、margin、padding、display等。重绘Repaint当元素的颜色、背景、边框阴影等不影响布局的属性变化时只需要重新画一次代价比回流小。优化原则很简单尽量避免频繁触发回流。几个非常实用的做法是批量修改 DOM 样式可以用classList一次性更换类名而不是一条一条改 style用transform代替top/left做动画因为transform不触发布局走的是合成层对需要多次读取布局属性的操作先读后写避免浏览器反复计算。另外还有脚本加载的阻塞问题。普通script标签会阻塞 HTML 解析所以要么放在/body前面要么用defer或async属性。这两个属性面试也爱问记住一句话区别defer会按顺序在 DOM 解析完成后执行async下载完就立刻执行、不保证顺序。2.3 浏览器缓存强缓存、协商缓存以及“版本号强制刷新”浏览器缓存是前端头等大事。后端明明更新了接口数据用户却还看到旧页面或者改了 CSS 文件名老用户刷新还是旧样式——这些都是缓存策略没配对导致的。浏览器缓存分两类强缓存和协商缓存。强缓存的字段是Cache-Control比如Cache-Control: max-age3600表示 1 小时内直接命本地缓存不发请求和老的Expires。命中强缓存的表现是Network 面板里请求显示(from memory cache)或(from disk cache)状态码直接 200。协商缓存的字段是ETag文件内容哈希和Last-Modified最后修改时间。浏览器发现强缓存过期后会带着If-None-Match或If-Modified-Since去找服务器确认服务器对比后发现没变化返回 304浏览器继续用本地缓存。前端最常见的操作是“通过版本号的变更让前端强制刷新页面”。实际做法有三层静态文件改名文件名带上内容 hash比如app.a3f2d1.js。内容变了 hash 就变浏览器请求新路径天然强制刷新这是构建工具Webpack、Vite默认支持的方案。在入口 HTML 里给静态资源手动加查询参数比如app.js?v1.0.1。改版本号后浏览器认为这是新资源会重新拉取。这个适合没有 hash 打包的简单项目。后端配置Cache-Control: no-cache给 HTML 入口文件这样每次都会回源校验而 hash 命名的资源可以放心设置max-age一年达到“入口实时更新、资源强缓存”的经典组合。2.4 浏览器调试利器DevTools 与内置浏览器负责前端的浏览器调试九成时间是在 Chrome DevTools 里度过的。建议优先熟悉的四个面板Elements看 DOM 和样式临时改样式排查布局问题。Console看日志和报错也是 JS 运行时最直接的反馈出口。Network看所有网络请求、状态码、资源加载时间跨域报错也在这里看响应头。Application看存储包括 LocalStorage、SessionStorage、Cookie、IndexedDB还有 Service Worker 和缓存。如果用的是 HBuilderX、VS Code 这类带内置浏览器的工具内置浏览器 debug 也可以做快速验证但真正到发布前的兼容性检查还是得回到 Chrome 和真实设备上。尤其是移动端谷歌浏览器提供“远程调试”能力手机开 USB 调试连电脑在chrome://inspect里就能看到手机页面的 Console 和 Network排查线上问题非常高效。一个我常用的快速验证缓存的小技巧在 Network 面板勾选Disable cache再配合右键请求选Clear browser cache可以快速还原“用户第一次打开页面”的状态用来验证首屏加载性能比手动清缓存快得多。3. 跨域问题全解与实用方案3.1 同源策略和跨域报错一眼看懂跨域CORS跨域资源共享是前后端分离开发中绕不开的坎。先明确同源的定义协议、域名、端口三者完全一致才是同源。换句话说https://a.example.com和http://a.example.com不同源http://example.com:8080和http://example.com:8081也不同源。浏览器强行规定前端页面只能自由请求同源地址跨源请求默认会被拦截。这样做的核心目的是安全——防止你登录了 A 网站后B 网站的恶意脚本偷偷替你去操作 A 的接口也就是防止 CSRF跨站请求伪造这类攻击。前端看到的最典型报错长这样Access to XMLHttpRequest at https://api.example.com/data from origin https://www.example.com has been blocked by CORS policy: No Access-Control-Allow-Origin header is present on the requested resource.这个英文报错翻译一下就是我请求了一个跨域地址响应里没有带上允许我这个源访问的响应头所以浏览器把结果拦下来了。3.2 简单请求与预检请求OPTIONS 是什么鬼跨域里有两个概念面试必问简单请求和预检请求Preflight。满足下面所有条件的请求才是简单请求方法为 GET、HEAD、POST 之一请求头里没有自定义头Authorization、X-Requested-With这种都不行且Content-Type只能是application/x-www-form-urlencoded、multipart/form-data、text/plain三者之一。只要不满足其中任意一条浏览器就会先发一个OPTIONS预检请求问服务器“我这次跨域请求带这些头和方法你允许吗”服务器确认允许后浏览器才发真正的业务请求。这就是为什么你用 axios 传application/json、或者带了Authorization头时Network 面板能看到两个请求一个是OPTIONS状态通常 204一个是实际请求。很多后端第一次联调时看到 OPTIONS 请求会很慌直接给个 404那前端真正请求也会被拦截。所以后端接口一定要针对 OPTIONS 放行。3.3 后端 CORS 配置绝大多数场景的标准答案跨域最正规的解决方案是后端配置 CORS 响应头。只要后端在响应里带上浏览器需要的头浏览器就不会拦截这是彻底解决跨域的关键。核心响应头配置如下Access-Control-Allow-Origin: https://www.example.com Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS Access-Control-Allow-Headers: Content-Type, Authorization Access-Control-Allow-Credentials: true Access-Control-Max-Age: 86400后端用 Node.jsExpress写的话加一个中间件就能实现app.use((req, res, next) { res.setHeader(Access-Control-Allow-Origin, https://www.example.com); res.setHeader(Access-Control-Allow-Methods, GET, POST, PUT, DELETE, OPTIONS); res.setHeader(Access-Control-Allow-Headers, Content-Type, Authorization); res.setHeader(Access-Control-Allow-Credentials, true); if (req.method OPTIONS) { res.sendStatus(204); return; } next(); });PHP 后端也可以直接在入口文件加头输出header(Access-Control-Allow-Origin: https://www.example.com); header(Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS); header(Access-Control-Allow-Headers: Content-Type, Authorization);配置里有几个隐藏的坑当需要携带 CookiewithCredentials: true时Access-Control-Allow-Origin不能写成*必须写具体域名还有如果用了Access-Control-Allow-Origin: *前端带自定义头照样会预检失败。遇到“后端说配了 CORS 但还是报错”的情况优先检查响应头里的 Allow-Origin 是否和当前页面源完全一致其次检查 Allow-Headers 是否覆盖了前端发送的所有自定义头。3.4 JSONP 原理与适用场景老方法但面试爱问JSONP 是早期的跨域方案原理非常巧妙浏览器加载script标签请求外部资源是不受同源策略限制的。所以前端可以动态创建一个script标签把跨域接口地址作为src后端返回一段 JavaScript 代码通常是函数调用这个函数就是前端预先定义好的回调函数数据作为参数传进来。前端核心实现差不多是这样function jsonp(url, callbackName, onSuccess) { const script document.createElement(script); script.src ${url}?callback${callbackName}; window[callbackName] onSuccess; document.body.appendChild(script); } jsonp(https://api.example.com/user, handleUser, (data) { console.log(data); });后端 PHP 配合方式也很简单$callback $_GET[callback] ?? ; $data json_encode([code 0, msg ok, data []]); if ($callback) { header(Content-Type: application/javascript); echo $callback . ( . $data . );; }JSONP 的局限非常明显只能发 GET 请求没法 POST并且依赖后端配合写回调。现在主流方案基本都用 CORS 了但面试官还是喜欢考察这个概念因为能检验你对浏览器加载机制和网络请求原理的理解深度。3.5 代理方案开发环境、线上 Nginx、Fiddler 抓包跨域的另一种常用思路是“绕开跨域”代理就是最典型的做法。开发环境里前端跑在本地localhost:3000后端接口在http://192.168.1.100:8080这种场景我几乎从不在代码里硬写后端完整地址而是在构建工具配置代理让浏览器始终只跟本地服务通信由本地服务去请求后端。Webpack devServer 配置devServer: { proxy: { /api: { target: http://192.168.1.100:8080, changeOrigin: true } } }Vite 大同小异server: { proxy: { /api: { target: http://192.168.1.100:8080, changeOrigin: true, rewrite: path path.replace(/^\/api/, ) } } }配置完以后前端代码里所有请求都写/api/xxx因为是同源请求浏览器不拦代理层再把请求转发到后端。changeOrigin: true的作用是把请求头里的 Host 改掉避免后端做域名校验时拒绝请求。线上环境的代理通常是 Nginx 反向代理配置类似location /api/ { proxy_pass http://backend-server:8080/; proxy_set_header Host $host; }另外还有一类工具Fiddler。它是抓包代理工具常用于本地调试线上接口或者老项目的跨域问题。原理是让所有浏览器请求都经过 FiddlerFiddler 在转发过程中改写请求头 Host或者给响应临时注入 CORS 头。这个方案适合调试和多环境切换但因为是客户端代理不会带到生产环境。3.6 跨域相关的扩展知识与记忆点除了 CORS、JSONP、代理这些主流方案还有几个偏冷门但面试偶尔提到的postMessageiframe 跨域通信的标准方式两个不同源页面之间传消息。document.domain把两边页面的 domain 设置为同一个父域适合主域名相同、子域名不同的情况。因为设置后可跨子域读取 Cookie 和 DOM所以越来越受安全策略限制。WebSocket不受同源策略限制因为 WebSocket 不走 HTTP 的 CORS 校验流程适合需要实时数据的跨域场景。前端 SDK 上报类需求也常碰到跨域比如第三方埋点 SDK 需要给不同客户的页面上报数据如果被上报方没有配置 CORS请求就会被拦截。稳妥做法是让后端上报接口配置好宽松的Access-Control-Allow-Origin或者在 SDK 内用sendBeacon配合降级方案确保前端主动发起的统计请求不被漏掉。4. Git 实战安装配置、日常命令与分支合并4.1 版本控制的定位与 Git 的“三区”模型Git 是目前前端开发绕不开的版本控制工具它的核心价值是不丢代码、可回溯、多人协作不打架。写错代码想看到昨天的版本用 Git 找回两个人改了同一个文件用 Git 合并并解决冲突。理解 Git 要从它的存储模型入手。最经典的是“三区”模型工作区你编辑器里看到的文件、暂存区通过git add放进去的待提交变更、版本库通过git commit永久保存的历史记录。平时开发里最标准的一次提交流程是这类命令的组合git status # 查看当前工作区状态 git diff # 查看具体改了什么 git add src/pages/Home.vue # 把指定文件放入暂存区 git commit -m feat: 新增首页轮播组件 # 提交到版本库 git push # 推送到远程仓库这个模型理解后很多操作就顺理成章了git checkout -- file是把工作区文件恢复成暂存区版本git reset --hard是把三个区全部恢复到指定版本git stash是先保存手头工作留出干净目录。4.2 Git 安装与全局配置环境搭好后面少踩坑Git 安装本身不难。Windows 直接下载官方安装包安装过程中建议勾选“Git Bash Here”和“Add to PATH”这两个选项后面在终端里直接用git命令会舒服很多。macOS 可以brew install gitLinux 发行版用各自包管理器安装比如apt install git。装完第一件事不是急着 clone 仓库而是配置全局用户信息这两个配置不设置commit 会失败或者提交的人名完全不对git config --global user.name yourname git config --global user.email youexample.comWindows 用户最好再配一行换行符转换git config --global core.autocrlf true原因是 Windows 换行符是 CRLFLinux/macOS 是 LF如果不做转换换行符差异会导致整个文件被标记为已修改diff 看哪儿都是红的。macOS/Linux 用户可以设成input效果是提交时自动转成 LF。还可以给常用命令配别名比如git config --global alias.st status git config --global alias.lg log --oneline --graph --all之后敲git lg就能看到清晰的提交历史分支图。配置完了用git config --list校验一下所有配置项是否正确加载。4.3 日常开发高频命令clone、add、commit、push、pull、log前端日常用 Git说白了就是一套固定的组合拳。我按使用频率整理成一张速查表命令场景说明git clone url拉取远程仓库到本地首次接手项目git status随时查看状态最常用的命令没有之一git add .暂存所有改动确认无误用否则指定文件git commit -m message提交代码message 要写清楚做了啥git pull --rebase拉取远程更新推荐加 --rebase避免多余 merge 记录git push推送到远程推送前先 pull 保持同步git log --oneline查看提交历史压缩显示一眼看清git branch -a查看所有分支本地和远端分支一起列出git checkout -b new-branch新建并切换分支开发新功能常用git merge xxx合并分支把 xxx 分支合入当前分支这里重点说git pull --rebase。直接git pull默认执行的是 merge 操作会在提交历史里多出一个Merge branch ...的提交记录长期下来历史会很乱。用--rebaseGit 会把当前分支没推送的提交临时拿下来拉取远程最新提交后再按顺序放回去历史是一条干净的直线。团队多人协作时这种干净历史对回溯很有用。4.4 分支合并实战merge、rebase、冲突解决分支是 Git 最强大的能力之一。我习惯的团队分支模型是main或者master保留稳定可发布的版本开发需求从main拉出feature/xxx分支修 bug 从main拉出bugfix/xxx分支合并时再合并回main。合并分支有两种方式git merge和git rebase。简单说merge 会保留所有人的完整提交历史形成分叉再汇合的网络rebase 会把当前分支的提交“搬家”到目标分支的历史后面形成线性历史。初学阶段用 merge 就好逻辑清楚、不容易出问题等理解深了再在个人开发分支上用 rebase 整理历史。真正考验人的是冲突处理。当两个分支改了同一个文件的同一块代码Git 无法自动判断取谁就会标出冲突。典型场景是我在feature/login分支改了一段样式main分支也改了这个文件的同一行代码合并时就会看到 HEAD console.log(本地分支的代码); console.log(feature/login 分支的代码); feature/login HEAD到之间是当前分支的内容到 feature/login之间是被合并分支的内容。手动改成想要的结果比如console.log(合并后的代码);删掉冲突标记符然后执行git add 文件路径 git commit -m fix: 解决登录页样式冲突冲突处理有个原则不要一个人闷头乱改。如果两个人各改了一半逻辑最好和对方沟通确认保留哪部分再定最终版本。合并后立刻跑一遍测试因为冲突解决错了不会报错只会埋下运行时 bug。4.5 常见报错排查SSH 认证失败与撤销操作Git 用久了总会碰到各种报错最经典的就是 SSH 认证失败报错信息类似Permission denied (publickey)。我第一次遇到时还以为是密码错了后来才发现是 SSH 公钥没配上。排查步骤按顺序来检查本地是否生成过 SSH keyls -al ~/.ssh正常情况下能看到id_rsa或id_ed25519和对应的.pub文件。没生成过就重新生成用 ed25519 更快更安全ssh-keygen -t ed25519 -C youexample.com一路回车即可文件默认生成在~/.ssh/id_ed25519。把公钥内容复制出来~/.ssh/id_ed25519.pub文件里整段以ssh-ed25519开头的内容添加到 Git 平台的 SSH Keys 设置里。测试连接是否打通ssh -T gitgithub.com能看到类似Hi xxx! Youve successfully authenticated的提示说明认证通过。国内常用的 Gitee、GitLab 验证命令也类似只是域名不同。还有一个高发问题如果当初 clone 用的是 HTTPS 方式而在某些托管平台上密码验证已关闭git push会报认证失败。解决办法是改用 Personal Access Token个人访问令牌作为密码输入或者改用 SSH 远程地址重新添加 remote。撤销操作也是必备技能。我做一次完整整理撤销工作区修改未 addgit checkout -- 文件恢复成上次提交/暂存的内容。撤销暂存已 add 未 commitgit reset HEAD 文件把文件从暂存区退回工作区。撤销上一次提交但保留改动git reset --soft HEAD~1。彻底丢弃最近 N 次提交git reset --hard HEAD~N这个要非常小心会丢失提交内容。已经 push 到远程了要安全撤销用git revert commit它会生成一个反向提交把代码改回去又保留了历史记录适合团队协作时使用。我个人的经验是git reset --hard这类命令只在自己的个人分支上使用公共分支一律用revert否则会把同事的本地历史搞得很难看甚至导致代码丢失。4.6 团队协作常见配合与提交规范前面说了命令但团队真正讲究的是“提交习惯”。我现在带的团队要求 commit message 遵循统一格式比如feat: 新增登录页记住密码功能 fix: 修复移动端键盘遮挡输入框问题 docs: 更新 README 部署说明 refactor: 重构订单列表状态管理简单一句话类型 冒号 描述。这样git log --oneline一眼能看出每个提交做了什么回滚时也能快速定位到具体某个功能或修复。写代码时有个好习惯是频繁提交、小而清晰。一次提交只做一件事一个提交只包含相关的文件改动。这比一天憋一个“更新代码”的大提交要健康得多审查代码和回溯都容易。用 IDEA、VS Code 这类 IDE 开发的朋友我建议命令和图形化配合着来。日常 add、commit、push 用 IDE 内嵌的 Git 面板没问题操作直观友好但遇到冲突解决、rebase、reset 这类高风险操作我会切到命令行因为能看到更完整的输出信息不容易被图形界面隐藏关键细节。最后提一个容易被忽略的配置.gitignore。新项目初始化时一定要尽早建立这个文件把node_modules/、dist/、.env、日志文件等不需要提交的内容排除掉。我见过同事把node_modules提交进仓库一次 push 好几百兆后面所有人 clone 都变慢这些都是可以提前规避的低级问题。总得来说这 15 天学下来最值钱的不是记了多少具体答案而是把 HTTP、浏览器、跨域、Git 这四块拼图连成了一整条线发请求时想着 HTTP 报文和连接复用调试时想着浏览器缓存和渲染流程遇到跨域时先分辨是简单请求还是预检请求每次提交代码时想着分支规范和排查路径。按我个人经验基础部分最忌讳死记硬背而是要多在真实项目里踩坑、记录、复述面试时才讲得出有细节的实战答案。接下来如果你正好有条件建议找几个线上接口多模拟联调和代理配置或者在团队仓库里主动承担分支管理和冲突解决的部分这种脚下踩泥巴式的学习效果比看十篇教程都有用。