一、概述

1. Web工作方式:

HTTP Request(请求)HTTP Response(响应)Response(body)

DNS域名服务器(Domain Name Server)是进行域名(domain name)和与之相对应的IP地址转换的服务器; DNS中保存了一张域名解析表;解析消息的域名;
一个Web服务器也被称为HTTP服务器, 它通过HTTP(HyperText Transfer Protocol 超文本传输协议)协议与客户端通信; 这个客户端通常指的是Web浏览器(其实手机端客户端内部也是浏览器实现的);
Web服务器的工作原理可以简单地归纳为:

TCP/IP

2. HTTP协议

超文本传输协议(HTTP, HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议, 它详细规定了浏览器和万维网服务器之间互相通信的规则, 通过因特网传送万维网文档的数据传送协议;
HTTP协议通常承载于TCP协议之上, 有时也承载于TLS或SSL协议层之上, 这个时候, 就成了HTTPS; 如下图所示:

3. 地址(URL)

Unique Resource Locationhttp、https、ftp
http://localhost[":"port][abs_path]
http://192.168.31.1/html/index
https://pan.baidu.com/

URL的长度有限制, 不同的服务器的限制值不太相同, 但是不能无限长;

二、HTTP报文解析:

1. 请求报文格式:


typeGETPOSTPOSTContent-TypeContent-Length

2.响应报文格式:

http的成功响应报文:

http的失败响应报文:

状态行、响应头部、空行、响应包体
HTTP 协议版本字段、状态码和状态码的描述文本
状态码含义
1xx表示服务器已接收了客户端请求,客户端可继续发送请求
2xx表示服务器已成功接收到请求并进行处理
3xx表示服务器要求客户端重定向
4xx表示客户端的请求有非法内容
5xx表示服务器未能正常处理客户端的请求而出现意外错误

常见的状态码举例:

状态码含义
200 OK客户端请求成功
400 Bad Request请求报文有语法错误
401 Unauthorized未授权
403 Forbidden服务器拒绝服务
404 Not Found请求的资源不存在
500 Internal Server Error服务器内部错误
503 Server Unavailable服务器临时不能处理客户端请求
  • 响应头部
    • 响应头可能包括:
响应头含义
LocationLocation响应报头域用于重定向接受者到一个新的位置
ServerServer 响应报头域包含了服务器用来处理请求的软件信息及其版本
Vary指示不可缓存的请求头列表
Connection连接方式
  • 空行:
    • 最后一个响应头部之后是一个空行, 发送回车符和换行符, 通知服务器以下不再有响应头部;
  • 响应包体:
    • 服务器返回给客户端的文本信息;
三、Go语言HTTP编程:
net/httpnet/http

1. 简单的服务端:

package main

import (
    "fmt"
    "net/http"
)

//服务端编写的业务逻辑处理程序 —— 回调函数
func myHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Println("method = ", r.Method) 	//请求方法
    fmt.Println("URL = ", r.URL)		// 浏览器发送请求文件路径
    fmt.Println("header = ", r.Header)		// 请求头
    fmt.Println("body = ", r.Body)		// 请求包体
    fmt.Println(r.RemoteAddr, "连接成功")  	//客户端网络地址

    w.Write([]byte("hello http")) 	//给客户端回复数据
}

func main() {
    http.HandleFunc("/hello", myHandler)	// 注册处理函数

    //该方法用于在指定的 TCP 网络地址 addr 进行监听,然后调用服务端处理程序来处理传入的连接请求。
    //该方法有两个参数:第一个参数 addr 即监听地址;第二个参数表示服务端处理程序,通常为nil
    //当参2为nil时,服务端调用 http.DefaultServeMux 进行处理
    http.ListenAndServe("127.0.0.1:8000", nil)
}
127.0.0.1:8000/hellomyHandlerfunc myHandler(w http.ResponseWriter, r *http.Request)
w http.ResponseWriterr *http.Request
type ResponseWriter interface {
   Header() Header			
   Write([]byte) (int, error)	
   WriteHeader(int)			
}
  • r 用来“接收客户端发送的数据”; 浏览器发送给服务器的http请求包的内容可以借助r来查看, 它对应一个结构体:
	type Request struct {
	Method string		// 浏览器请求方法 GET、POST…
	URL *url.URL		// 浏览器请求的访问路径
	……
	Header Header		// 请求头部
	Body io.ReadCloser	// 请求包体
	RemoteAddr string	// 浏览器地址
	……
    	ctx context.Context
}

查看一下结构体成员:

fmt.Println("Method = ", r.Method)
fmt.Println("URL = ", r.URL)
fmt.Println("Header = ", r.Header)
fmt.Println("Body = ", r.Body)
fmt.Println(r.RemoteAddr, "连接成功")

2. 简单的客户端:

func Get(url string) (resp *Response, err error)Response
type Response struct {
   Status     string // e.g. "200 OK"
   StatusCode int    // e.g.  200
   Proto      string // e.g. "HTTP/1.0"
   ……
   Header Header
   Body io.ReadCloser
   ……
}
Close()
package main

import (
   "net/http"
   "fmt"
)

func main()  {
   // 使用Get方法获取服务器响应包数据
   //resp, err := http.Get("http://www.baidu.com")
   resp, err := http.Get("http://127.0.0.1:8000/hello")
   if err != nil {
      fmt.Println("Get err:", err)
      return
   }
   defer resp.Body.Close()

   // 获取服务器端读到的数据
   fmt.Println("Status = ", resp.Status)           // 状态
   fmt.Println("StatusCode = ", resp.StatusCode)   // 状态码
   fmt.Println("Header = ", resp.Header)           // 响应头部
   fmt.Println("Body = ", resp.Body)               // 响应包体

   buf := make([]byte, 4096)         // 定义切片缓冲区,存读到的内容
   var result string
   // 获取服务器发送的数据包内容
   for {
      n, err := resp.Body.Read(buf)  // 读body中的内容。
      if n == 0 {
         fmt.Println("Body.Read err:", err)
         break
      }
      result += string(buf[:n])     // 累加读到的数据内容
   }
   // 打印从body中读到的所有内容
   fmt.Println("result = ", result)
}