# Web 基础架构
## 1. Web 类型
- **静态 Web**: 所有用户看到的内容完全相同
- **动态 Web**: 根据用户身份、权限等展示不同内容
## 2. Web 应用架构
- **B/S (Browser/Server)**: 基于浏览器的 Web 应用
- **C/S (Client/Server)**: 需要安装的客户端程序
- 优势: 跨平台支持 (Windows/Mac/Linux)
## 3. 网络协议
- **HTTP**:
- 标准端口: 80
- 用途: 传输超文本(文本、图片、视频等)
- **HTTPS**:
- 标准端口: 443
- 特点: 加密传输,更安全
## 4. 通信模型
**请求-响应模式**:
- 请求 (Request):
- 来源: 客户端(浏览器)
- 内容: URL 地址(如 https://www.baidu.com)
- 方式: GET、POST、PUT、DELETE 等
- 响应 (Response):
- 来源: 服务端
- 功能: 处理请求并返回数据
- 主要操作: CRUD(增删改查),占比约 80%
## 5. 工作流程
1. 客户端通过 TCP/IP 连接服务器
2. 发送 HTTP(S) 请求:
- 普通请求: www.example.com/login?username=xxx&pwd=xxx
- 文件上传: upload/video?file=xxx
3. 服务器处理请求
4. 返回响应结果
5. 客户端展示结果
6. 断开连接
## 开发调试
- 使用浏览器开发者工具 (F12 或右键检查)
- 分析请求/响应数据
- 优化代码性能和健壮性
# helloworld
go 语言中所有和网络相关的都在 net 包下,http 也在 net 包下。
包含了客户端和服务端的代码实现。
未来我们学习的所有框架,都是基于这些底层代码的。
请求(request)- 响应(response)
```go
package main
import (
"fmt"
"net/http"
)
// 一个简单的服务端代码实现
// http程序启动之后是不会停止的,一直监听请求
func main() {
// 写一些请求来接收浏览器的信息
// HandleFunc http请求的处理函数
// func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
// localhost:8080/hello url -> 代码处理
http.HandleFunc("/hello", hello)
// 有一个地址给浏览器访问,什么都没有。404
// func ListenAndServe(addr string, handler Handler)
// localhost 本机(127.0.0.1) : 端口 (8080)
// nil默认处理器,空的 404
// 开启监听程序的代码是放在main方法的最后一行的。
http.ListenAndServe("localhost:8080", nil)
}
// 请求和响应
func hello(resp http.ResponseWriter, req *http.Request) {
// 查看一些请求信息 (/login:用户名和密码来匹配登录 /user/id 接收用户的id然后查询用户信息 )
fmt.Println(req.URL)
fmt.Println(req.Method)
fmt.Println(req.RemoteAddr)
//...
// 一般会响应一些信息给客户端 (文字、网页) resp.Write
// 响应一段文字[]byte("hello,web")
// 响应一段html代码 []byte("html代码") 网页
resp.Write([]byte("
hello,web
"))
}
```
代码来写客户端
```go
package main
import (
"fmt"
"io"
"net/http"
)
// 手写客户端访问
func main() {
/*
http.Get()
*/
// 请求方式 请求的url 接收响应结果
resp, _ := http.Get("http://localhost:8080/hello")
// 通过defer关闭连接 resp.Body 响应的主体
defer resp.Body.Close()
fmt.Println(resp.Body)
fmt.Println(resp.Status) // 200 OK
fmt.Println(resp.Header) // 响应头
// 接收具体的响应内容
buf := make([]byte, 1024)
for {
n, err := resp.Body.Read(buf)
if err != nil && err != io.EOF {
fmt.Println("读取出现了错误")
return
} else {
fmt.Println("读取完毕")
res := string(buf[:n])
fmt.Println("服务器响应的数据为:", res)
break
}
}
}
```
# 带参数的请求
客户端编写
- url的参数拼接 ?拼接 & 连接
```go
package main
import (
"fmt"
"io"
"net/http"
"net/url"
)
func main() {
// 复杂请求
urlStr := "http://127.0.0.1:8080/login" // ?
// 参数如何拼接到url上,参数封装为数据url.Values{}
data := url.Values{}
data.Set("username", "admin") // ?
data.Set("password", "123456") // ?
// 将url字符串转化为url对象,并给携带数据
urlNew, _ := url.ParseRequestURI(urlStr)
urlNew.RawQuery = data.Encode()
// http://127.0.0.1:8080/login?password=123456&username=kuangshen
// ? get的传参,多个参数之间使用 & 连接
fmt.Println(urlNew)
// 发请求,参数是一个地址
resp, _ := http.Get(urlNew.String())
defer resp.Body.Close()
// 读取resp信息,返回buf
buf, _ := io.ReadAll(resp.Body)
fmt.Println(string(buf))
}
```
后台处理代码
```go
func login(resp http.ResponseWriter, req *http.Request) {
// 模拟数据库中存在一个数据
mysqlUserData := "admin"
mysqlPwdData := "123456"
fmt.Println("接收到了login请求")
// 拿到请求中的参数
urlData := req.URL.Query()
username := urlData.Get("username")
password := urlData.Get("password")
// 登录逻辑, 将客户端发送的数据和系统数据比对实现登录业务
if username == mysqlUserData {
if password == mysqlPwdData {
resp.Write([]byte("登录成功"))
} else {
resp.Write([]byte("密码错误"))
}
} else {
resp.Write([]byte("登录失败"))
}
}
```
# 表单参数获取
html表单
```html
登录
```
后端处理代码
```go
func register(resp http.ResponseWriter, req *http.Request) {
fmt.Println("接收到了注册请求")
// 处理表单的请求, 前端提交表单-后盾解析表单
req.ParseForm() // 解析表单
// 获取表单参数 post
username := req.PostForm.Get("username")
password := req.PostForm.Get("password")
fmt.Println(username, password)
// 很多的判断
// 短信
// 验证码
resp.Write([]byte("注册成功"))
}
```
# 要给前端响应数据 (了解即可)
- 我们给前端数据
- 页面模板要渲染数据!有很多语法,看看就好。类似于Java中的JSP 、或者PHP里面的代码
- 代码+页面融合,很乱,已经被这个时代抛弃了
- 前后端分离(我们后面都用这种方式)
1、通过代码跳转到页面 template
```go
// 通过请求,进入页面(路由) temp.Execute(resp, data)
// 通过URl进入某个页面
func findAll(resp http.ResponseWriter, req *http.Request) {
// 接收到前端的信息 /findAll, 查询全部用户
userMap := make(map[int]User)
userMap[1] = User{"KUANGSHEN", 1}
userMap[2] = User{"xiaoming", 2}
// 返回给前端页面并渲染上去
temp, _ := template.ParseFiles("./userlist.html")
data := make(map[string](map[int]User))
data["data"] = userMap
temp.Execute(resp, data)
}
```
2、前端的一些简答语法(了解即可,和php、jsp、C#差不多)
```html
查询用户
{{range $k,$v := .data}}
{{$k}}
{{if eq $k 1}}
{{.Name}}
{{$v}}
{{end}}
{{end}}
```