Appearance
元信息
- 目标:亲手搭建"前端表单页 + 后端 PHP 脚本"的最小前后端交互,提交、观察、破坏、修复,体会两者的分工与依赖
- 关键概念:action 与 method、请求与响应、回显、GET/POST 语义、前后端依赖
- 关联阶段:cp1
- 常见误区:以为提交不是 HTTP 请求(提交就是 POST 到 action 地址的一个请求,浏览器随后显示该响应);以为前端页面与后端脚本各不相干(第 5 步的三个破坏性实验逐一击破)
第 1 步:编写前端表单页面
在站点目录 htdocs/form 下新建 form.html:
要点:每个输入控件都有 name 属性——它是数据提交时的"字段名",没有 name 的控件不会被提交。action 指向后端地址,method 指定 HTTP 动词。
第 2 步:编写后端脚本
同目录下新建 save.php(即表单中的回显脚本):
php
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>提交结果</title></head>
<body>
<h3>服务器收到以下数据:</h3>
<ol>
<?php
foreach ($_POST as $key => $value){
echo "<li>{$key} : {$value}</li>";
}
?>
</ol>
<a href="./form.html">返回表单</a>
</body>
</html>注意:.php 文件和 .html 文件放在同一目录——它们是同一站点里的两个页面,一个负责采集,一个负责处理。
第 3 步:提交并观察
浏览器访问
http://form.x.com/form.html(或http://localhost/form/form.html)修改输入框内容,点击"提交留言"
应看到 save.php 返回的列表:
nickname : 你填的值、message : ...、channel : ...按 F12 打开 devtools → Network(网络)面板,找到
save.php这条请求,查看:- Payload/表单数据:你提交的字段名和值
- Response(响应):服务器返回的 HTML——正是你现在看到的页面
这一步是本任务的核心:亲眼确认"提交 = 一个 POST 请求",请求和响应都是完整的 HTTP 报文。
第 4 步:改成 GET,对比观察
把 form.html 的 method="post" 改为 method="get"(save.php 中的 $_POST 也要改为 $_GET),再次提交,观察三处变化:
- 地址栏:变成了
save.php?nickname=tom&message=...——数据跑到了 URL 查询字符串里 - devtools:请求的 Payload 不再有请求体,数据在 URL 上
- 刷新页面:GET 提交后刷新会重复请求(幂等),POST 刷新会弹出"重新提交表单?"警告——这就是两者语义区别的直观体现
结论对照表单中 GET/POST 的对比表:GET 数据在 URL、语义只读;POST 数据在报文体、语义写入。
第 5 步:把后端"改坏",理解依赖关系
依次做三个破坏性实验,每次改完刷新或重新提交:
- 改掉 action:把
action="./save.php"改为不存在的./savex.php,提交——得到 404。说明前端表单依赖后端地址真实存在 - 把 save.php 改名为 save.txt,提交——浏览器可能把文件当附件下载。原因:Apache 只把
.php交给 PHP 引擎执行,其他扩展名按普通文件直接返回(见表单中的错误分析) - 停掉 Apache(XAMPP 面板 Stop),访问表单——整个站点都不可达。说明前端页面本身也是从服务器获取的
三个实验共同回答"前端页面和后端脚本之间的关系":同属一个站点、通过 HTTP 的一问一答协作、任何一环断裂交互即失败。
第 6 步(选做):让后端真正"记住"数据
把 save.php 的 PHP 部分改为写入文件,模拟一次真正的"存储":
php
<?php
$file = fopen("db.txt", "a");
foreach ($_POST as $key => $value){
fputs($file, "{$key} : {$value}\n");
}
fclose($file);
echo "<p>留言已保存,<a href='./db.txt'>查看数据文件</a></p>";
?>提交几次后打开 db.txt:数据已经持久化在后端磁盘上。注意这里用了 "a"(追加)模式而不是 "w"(覆盖)。这就是"后端处理"的最小实例——真实站点无非是把 db.txt 换成数据库。
ntfy 方案:免环境的外部后端
PHP方案胜在完整:后端代码每一行都自己写。如果 XAMPP 一时没配好,也可以先用公共的 ntfy.sh 当后端:它是一个公开的消息服务,接受任意 POST,把收到的内容临时存储 12 小时。零安装、零代码。
与此相似的是 https://httpbin.org 但它只echo,不保存
做法:把 form.html 另存一份为 form-ntfy.html,只改一处——action 指向一个自命名的"频道"(topic):
用浏览器直接打开 form-ntfy.html 提交几次表单(相当于用POST方式),然后访问链接(相当于用GET方式) https://ntfy.sh/webfront-save:所有提交按时间排列,这就是主路第 6 步 db.txt 的网页版。
两个细节
- 提交后的"结果页"是一段 JSON 回执——它不是你写的 PHP 生成的,而是 ntfy 的服务器生成的
- 中文变成了
nickname=%E5%B0%8F%E6%98%8E这样的百分号编码——这才是线上真正传输的格式。主路里 PHP 的$_POST已经替你解码,所以你从没见过它;对照curl 实训第 4 步的title=hello&body=world,是同一件事
两条路对照,正是"后端"的两种现实形态:
| xampp + PHP(主路) | ntfy.sh(辅路) | |
|---|---|---|
| 后端代码 | 自己写、自己改 | 服务商写好,你只是调用 |
| 运行环境 | 自己的机器(XAMPP) | 别人的服务器 |
| 存储行为 | 自己定义(db.txt 永久保存) | 固定:存 12 小时后过期 |
| 换后端 | 改代码、换目录 | 只改 action 一个属性 |
最后一点值得单独强调:前端根本不关心后端是谁——action 指向哪里,数据就提交到哪里。主路换辅路,改的只是这一个地址。
注意:topic 名公开可读,取名带上学号或随机后缀;同一出口 IP 高频提交会被限流(返回 429),分批提交即可。
验收标准
- [ ] form.html 与 save.php 部署在本地站点,GET/POST 两种方式提交成功
- [ ] 能在 devtools 中指出一次表单提交的请求方法、URL、负载数据与响应内容
- [ ] 完成第 5 步的三个破坏性实验,并能解释每个现象
- [ ] (选做)db.txt 能累积保存多次提交
- [ ] (选做)ntfy 辅路提交成功,能说出与 PHP 主路的两点不同