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
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.Write([]byte("this is a Web server"))
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("/", 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
StatusCode int
Proto string
……
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() {
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)
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])
}
fmt.Println("result = ", result)
}