文章目录

web工作方式:

1. 客户端 ——> 访问 www.baidu.com  ——> DNS 服务器。 返回 该域名对应的 IP地址。

2. 客户端 ——> IP + port ——> 访问 网页数据。(TCP 连接。 HTTP协议。)

http和URL:

http 超文本传输协议。规定了 浏览器访问 Web服务器 进行数据通信的规则。  http(明文) -- TLS、SSL -- https(加密)

URL:统一资源定位。 在网络环境中唯一定位一个资源数据。  浏览器地址栏内容。

http请求包:

请求行:请求方法(空格)请求文件URL(空格)协议版本(\r\n)

	GET、POST

请求头:语法格式 : key :value

空行:\r\n	 —— 代表 http请求头结束。

请求包体:请求方法对应的数据内容。 GET方法没有内容!!

http应答包测试:

1. 使用 net/http包 创建 web 服务器

	1) 注册回调函数。
		
		http.HandleFunc("/itcast", handler)

			参1:用户访问文件位置

			参2:回调函数名 —— 函数必须是 (w http.ResponseWriter, r *http.Request) 作为参数。

	2)绑定服务器监听地址。

		http.ListenAndServe("127.0.0.1:8000", nil)
2. 回调函数:

	本质:函数指针。通过地址,在某一特定位置,调用函数。

	在程序中,定义一个函数,但不显示调用。当某一条件满足时,该函数由操作系统自动调用。 

http应答包格式:

状态行:协议版本号(空格)状态码(空格)状态码描述(\r\n)

响应头:语法格式 : key :value

空行:\r\n

响应包体: 请求内容存在: 返回请求页面内容

	 请求内容不存在: 返回错误页面描述。

http WEB服务器:

1.  注册回调函数:http.HandleFunc("/", myHandler)

	func myHandler(w http.ResponseWriter, r *http.Request)

		w:给客户端回发数据

		r:从客户端读到的数据

	type ResponseWriter interface {
	   	Header() Header			
   		Write([]byte) (int, error)	
   		WriteHeader(int)			
	}
	type Request struct {
		Method string		// 浏览器请求方法 GET、POST…
		URL *url.URL		// 浏览器请求的访问路径
		……
		Header Header		// 请求头部
		Body io.ReadCloser	// 请求包体
		RemoteAddr string	// 浏览器地址
		……
			ctx context.Context
	}

2. 绑定服务器地址结构:http.ListenAndServe("127.0.0.1:8000", nil)

	参2:通常传 ni 。 表示  让服务端 调用默认的 http.DefaultServeMux 进行处理	
package main

import (
	"net/http"
	"fmt"
)

func myHandle(w http.ResponseWriter, r *http.Request) {
	// w : 写给客户端的数据内容
	w.Write([]byte("this is a Web server"))

	// r: 从客户端读到的内容
	fmt.Println("Header:", r.Header)
	fmt.Println("URL:", r.URL)
	fmt.Println("Method:", r.Method)
	fmt.Println("Host:", r.Host)
	fmt.Println("RemoteAddr:", r.RemoteAddr)
	fmt.Println("Body:", r.Body)
}

func main()  {
	// 注册回调函数, 该函数在客户端访问服务器时,会自动被调用
	//http.HandleFunc("/itcast", myHandle)
	http.HandleFunc("/", myHandle)

	// 绑定服务器监听地址
	http.ListenAndServe("127.0.0.1:8000", nil)
}

WEB服务器练习:将本地文件写到浏览器

package main

import (
	"net/http"
	"fmt"
	"os"
)

func OpenSendFile(fNmae string, w http.ResponseWriter)  {
	pathFileName := "C:/itcast/test" + fNmae
	f, err := os.Open(pathFileName)
	if err != nil {
		fmt.Println("Open err:", err)
		w.Write([]byte(" No such file or directory !"))
		return
	}
	defer f.Close()

	buf := make([]byte, 4096)
	for {
		n, _ := f.Read(buf)			// 从本地将文件内容读取。
		if n == 0 {
			return
		}
		w.Write(buf[:n])			// 写到 客户端(浏览器)上
	}
}

func myHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Println("客户端请求:", r.URL)
	OpenSendFile(r.URL.String(), w)
}

func main()  {
	// 注册回调函数
	http.HandleFunc("/", myHandler)
	// 绑定监听地址
	http.ListenAndServe("127.0.0.1:8000", nil)
}

http WEB客户端:

1. 获取web服务器数据:

	func Get(url string) (resp *Response, err error)

	返回:http应答包,保存成 struct 

	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
  		 ……
	}
2. defer resp.Body.Close()

3. for 循环提取 Body 数据:

	n, err := resp.Body.Read(buf) 
	if n == 0 {
		fmt.Println("--Read finish!")
		break
	}
	if err != nil && err != io.EOF {
		fmt.Println("resp.Body.Read err:", err)
		return
	}
package main

import (
	"net/http"
	"fmt"
	"io"
)

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("--Read finish!")
			break
		}
		if err != nil && err != io.EOF {
			fmt.Println("resp.Body.Read err:", err)
			return
		}

		result += string(buf[:n])     // 累加读到的数据内容
	}
	// 打印从body中读到的所有内容
	fmt.Println("result = ", result)
}