Files
notes/resource/go/待总结/015 Go 语言 http 编程.md
2026-03-01 01:43:46 +08:00

7.3 KiB
Raw Permalink Blame History

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

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("<h1 style=\"color: red;\">hello,web</h1>"))

}

代码来写客户端

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的参数拼接 ?拼接 & 连接
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))
}

后台处理代码

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表单

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>

<!--表单-->
<!--http://localhost:8080/register?username=kuangshen&password=123456-->
<form action="http://localhost:8080/register" method="post">
    <h2>注册</h2>
    <p>用户名:<input type="text" name="username"></p>

    <p>密码:<input type="password" name="password"></p>

    <input type="submit" value="注册">

</form>

</body>
</html>

后端处理代码

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

// 通过请求,进入页面(路由)  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#差不多)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>查询用户</title>
</head>
<body>
<!--获取后端的数据 {{.data}}
遍历
{{range $k,$v := .data}}

{{end}}

-->

{{range $k,$v := .data}}
    {{$k}}
    {{if eq $k 1}}
        {{.Name}}
        {{$v}}
    {{end}}
{{end}}

</body>
</html>