🥰个人主页:会编程的土豆(欢迎来访)
💎作者简介:后端学习者
❄️个人专栏:数据结构与算法,数据库,leetcode
✨那些你一个人走过的夜路,终将化作照亮未来的光
学 Web 的时候,很多人会卡在一件事上:
我点了个按钮,后端怎么知道?页面为什么有时会刷新,有时又只变一小块字?
我在跟一个 Go 标准库写的网上书城时,把交互大致分成了两类:
- 整页跳转:点链接、提交表单,地址栏变了,整页刷新
- Ajax 局部更新:JS 偷偷发请求,地址栏不变,只改页面一小块
下面按这个项目里的真实写法展开。看完最好自己点一遍「查价格」和「加入购物车」,体感会差很多。
1. 先记结论
| 整页跳转 | Ajax | |
|---|---|---|
| 谁发请求 | 浏览器按 HTML 规则发 | JS(如 jQuery/fetch)发 |
| 地址栏 | 通常会变 | 通常不变 |
| 页面 | 整页换成新 HTML | 不整页刷新,JS 改局部 |
| 后端常回什么 | 一整页 HTML | 一小段文字或 JSON |
| 书城例子 | 查价格、翻页、登录 | 加购、改购物车数量 |
两种都是 HTTP 请求,差别主要在:谁发起、回来之后浏览器怎么处理。
2. 方式一:整页跳转(点链接 / 提交表单)
2.1 点链接
页面上常见这种:
<a href="/getPageBooksByPrice?pageNo=2&min=20&max=30">下一页</a>你一点「下一页」:
- 浏览器读取
href - 向服务器请求这个地址(一般是 GET)
- 服务器返回一整页 HTML
- 浏览器扔掉旧页面,显示新页面
- 地址栏变成新的 URL
参数直接写在 URL 的?后面,后端用r.FormValue("pageNo")之类就能取到
2.2 提交表单
书城首页查价格类似:
<form action="/getPageBooksByPrice" method="POST"> 价格:<input type="text" name="min"> 元 - <input type="text" name="max"> 元 <button>查询</button> </form>一点「查询」:
- 浏览器找到这个
<form> - 看
action(寄到哪)和method(GET 还是 POST) - 收集带
name的输入框,比如min=20&max=30 - 发 HTTP 请求到
/getPageBooksByPrice - 服务器查库、填充模板,返回新的
index.html - 浏览器整页刷新显示结果
POST 时请求大概长这样(示意):
POST /getPageBooksByPrice HTTP/1.1 Host: 127.0.0.1:8080 Content-Type: application/x-www-form-urlencoded min=20&max=30注意:URL 不是“前端另外去获取”的,而是写在action/href里的;浏览器负责按规则发包。
2.3 后端这边在干什么
以查价格为例,路径在main.go里挂到 controller,例如:
/getPageBooksByPrice → GetPageBooksByPrice函数里大致:
FormValue取出pageNo、min、max- 调 dao 查数据库(可按价格筛,再分页)
template.ParseFiles+Execute(w, page)把数据填进 HTML- 整页 HTML 通过响应返回浏览器
特点就是:几乎不靠 JSON,回来就是一张新网页
登录、注册、看购物车页、翻页,很多都是这一类
3. 方式二:Ajax 局部更新(JS 发请求)
3.1 为什么需要它?
加购如果也整页刷新,体验很差:点一下「加入购物车」,整个首页闪一下重载
更合理的是:
- 页面还在
- 后台把书加进购物车
- 页面上只提示一句「已加入,当前共 x 件」
这就是 Ajax 的典型场景。
3.2 书城里怎么写
项目用的是 jQuery,大意是:
$(".addBook2Cart").click(function () { var bookId = $(this).attr("id"); $.post("/addBook2Cart", { bookId: bookId }, function (res) { // 根据返回内容更新提示文字、购物车数量等 }, "json"); });和整页跳转的差别:
- 不是浏览器自动按
<form>/<a>跳走 - 是JS 在当前页发 HTTP 请求
- 地址栏可以完全不变
- 返回内容由 JS 自己处理,而不是整页替换
用fetch也能做同类事,思想一样:JS 发请求,自己处理响应。
3.3 后端怎么回
AddBook2Cart这类接口通常:
- 从请求里取
bookId(以及 Cookie,判断登录) - 改数据库购物车
- 不渲染整页模板,而是往
w里写一小段结果
成功时可能回 JSON,例如:
{"ok":true,"msg":"已将《边城》加入购物车","totalCount":3}失败时也可能回纯文字,比如"请先登录!"。
前端拿到后:
- 若是「请先登录」→ 跳登录页
- 若是成功 JSON → 把提示写到页面某个
<span>里
页面主体还在,只动了一小块。
改购物车数量也类似:输入框change后发 Ajax,回来更新总价、小计,不必整页刷新。
4. 两条路对比着记
相同点
- 都是浏览器(或 JS)向某个 URL 发 HTTP 请求
- 都由
main.go按路径匹配到 Go 函数 - 后端都能从请求里取参数、查库、写响应
不同点
| 环节 | 整页跳转 | Ajax |
|---|---|---|
| 触发 | <a>/<form> | 按钮绑定的 JS |
| 发请求的“人” | 浏览器导航机制 | 你的脚本 |
| 响应内容 | 完整 HTML 文档 | 文本 / JSON 等“碎片” |
| 浏览器默认行为 | 用新文档替换当前页 | 几乎不管,交给回调函数 |
| 地址栏 | 变 | 一般不变 |
一句话:
整页跳转是“换一张完整网页”;Ajax 是“要一小段数据,自己改页面”。
5. 结合书城:哪些功能属于哪一类
更偏整页跳转
- 首页
/main - 价格查询、分页链接
- 登录 / 注册(表单提交后换页)
- 打开购物车页
/getCartInfo - 我的订单、后台图书列表
- 注销后跳转首页
更偏 Ajax
- 加入购物车
/addBook2Cart - 修改购物车某项数量
/updateCartItem - 注册时检查用户名是否可用
/checkUserName
同一个项目里两种都会用:页面跳转负责“换场景”,Ajax 负责“当前页上的小动作”。
6. 后端视角:都是 URL → 函数,差在“回什么”
很多人以为 Ajax 很神秘。其实对 Go 标准库来说,入口差不多:
请求打到某个路径 → HandleFunc 找到对应 controller → 用 r 读参数 → 用 w 写回去差别主要在写回去的内容:
- 整页:
template.Execute(w, data)→ HTML - Ajax:
w.Write(...)或json.NewEncoder(w).Encode(...)→ 短文本/JSON - 有时还有:
http.Redirect→ 告诉浏览器再去另一个地址(也常伴随整页变化)
所以学后端时,不必把 Ajax 想成另一套协议,它还是 HTTP;只是前端处理响应的方式不同。
7. 一个容易混的点:参数在哪
不管整页还是 Ajax,参数常见几种放法:
- URL 查询串:
?pageNo=2&min=20 - 表单体:
min=20&max=30(application/x-www-form-urlencoded) - JSON 体:
{"bookId":"5"}(很多现代 API 爱用;本课设加购更常见的是表单字段 POST)
Go 里经常用r.FormValue("xxx")读前两种。
读 JSON 则要解析 body,和 FormValue 不是同一条路。
书城课设:表单 + URL 参数为主,Ajax 成功时响应侧 JSON 更多一些
- 点「查询价格」,看地址栏和页面是否整页刷新
- 登录后点「加入购物车」,看地址栏是否不变、提示是否局部出现
- 打开浏览器开发者工具 Network 面板:
- 整页请求的响应类型多半是
document/ HTML - Ajax 请求的响应可能是 JSON 或一小段 text
- 整页请求的响应类型多半是
再对照main.go里路径对应哪个函数,基本就能串起来。
9. 收束
我自己是这么记的:
- 整页跳转:链接和表单是主角,浏览器换页,后端爱回 HTML
- Ajax:JS 是主角,页面不走,后端爱回“小数据”,前端自己改 DOM
这个 Go 书城恰好两种都有:逛书、筛选、登录走整页;加购、改数量走 Ajax。
把这两条请求链路都跟一遍,前后端怎么交互就不容易再懵了。
如果要写成系列,下一篇可以专门拆一次:AddBook2Cart从点击到 JSON 返回的完整调用链(controller → dao → 再写回w)。