# 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}} ```