一、HTTP
1.http编程(http是文本协议,socket是二进制协议)
a.Go原生支持http,import(“net/http”) b.Go的http服务性能和nginx 比较接近 c. 几行代码就可以实现 一个web服务
http请求包
GET /domains/example/ HTTP/1.1 //请求行: 请求方法 请求URI HTTP协议/协议版本Host:www.iana.org //服务端的主机名User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari///浏览器 信息Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 //客户端能接收的mineAccept-Encoding:gzip,deflate,sdch //是否支持流压缩Accept-Charset:UTF-8,*;q=0.5 //客户端字符编码集//空行, 用于分割请求头和消息体//消息体,请求资源参数,例如POST传递的参数
http响应包
HTTP/1.1 200 OK //状态行 Server: nginx/1.0.8 //服务器使用的WEB软件名及版本Date:Date: Tue, 30 Oct 2012 04:14:25 GMT //发送时间 Content-Type: text/html //服务器发送信息的类型 Transfer-Encoding: chunked //表示发送HTTP包是分段发的,http/1.0是全部一起发,http/1.1是一段一段的发 Connection: keep-alive //保持连接状态 Content-Length: 90 //主体内容长度 //空行用来分割消息头和主体
发送http请求
package mainimport ( "fmt" "io" "net")func main() { conn, err := net.Dial("tcp", "www.baidu.com:80") if err != nil { fmt.Println("Error dialing", err.Error()) return } defer conn.Close() msg := "GET / HTTP/1.1\r\n" msg += "Host: www.baidu.com\r\n" msg += "Connection: close\r\n" msg += "\r\n\r\n" _, err = io.WriteString(conn, msg) if err != nil { fmt.Println("write string failed, ", err) return } buf := make([]byte, 4096) for { count, err := conn.Read(buf) if err != nil { break } fmt.Println(string(buf[0:count])) }}
HTTP服务端
package mainimport ( "fmt" "net/http")func Hello(w http.ResponseWriter, r *http.Request) { //r 是请求头信息 fmt.Println("handle hello") fmt.Fprintf(w, "hello ") //将数据返回给客户端}func main() { http.HandleFunc("/", Hello) err := http.ListenAndServe("0.0.0.0:8880", nil) //检测端口,解析请求,分发请求进行处理 if err != nil { fmt.Println("http listen failed") }}
HTTP客户端
package mainimport ( "fmt" "io/ioutil" "net/http")func main() { res, err := http.Get("https://www.baidu.com/") if err != nil { fmt.Println("get err:", err) return } data, err := ioutil.ReadAll(res.Body) //读取网络链接里面数据 if err != nil { fmt.Println("get data err:", err) return } fmt.Println(string(data))}
2.http常见请求方法
1)Get请求
2)Post请求
3)Put请求
4)Delete请求
5)Head请求
Head请求头
package mainimport ( "fmt" "net/http")var url = []string{ "http://www.baidu.com", "http://google.com", "http://taobao.com",}func main() { for _, v := range url { resp, err := http.Head(v) //Head请求时只会返回响应头 if err != nil { fmt.Printf("head %s failed, err:%v\n", v, err) continue } fmt.Printf("head succ, status:%v\n", resp.Status) }}
3.http 常见状态码
http.StatusContinue = 100 //继续访问http.StatusOK = 200http.StatusFound = 302 //跳转http.StatusBadRequest = 400 //发送的请求,协议格式不对http.StatusUnauthorized =401 //没有授权http.StatusForbidden = 403 //没有权限访问http.StatusNotFound = 404 //请求地址不存在http.StatusInternalServerError = 500 //服务器有问题502 //有代理,后端服务挂了504 //后端处理请求超时
4、表单处理
package mainimport ( "io" "net/http")const form =``func SimpleServer(w http.ResponseWriter, request *http.Request) { io.WriteString(w, "
hello, world
") //返回h1标签至前端渲染}func FormServer(w http.ResponseWriter, request *http.Request) { w.Header().Set("Content-Type", "text/html") //设置响应头 w.Header().Set("Server", "Go 1.9.2 Server") w.Header().Set("Niubi", "hahahaha") switch request.Method { case "GET": io.WriteString(w, form) case "POST": request.ParseForm() //解析post请求,才能得到请求内容 io.WriteString(w, request.Form["username"][0]) //go支持文本框name相同 io.WriteString(w, "\n") io.WriteString(w, request.FormValue("username"))//取不到内容返回空 }}func main() { http.HandleFunc("/test1", SimpleServer) http.HandleFunc("/test2", FormServer) if err := http.ListenAndServe(":8088", nil); err != nil { }}5、panic处理
package mainimport ( "io" "net/http" "log")const form = ``func SimpleServer(w http.ResponseWriter, request *http.Request) { io.WriteString(w, "
hello, world
")}func FormServer(w http.ResponseWriter, request *http.Request) { w.Header().Set("Content-Type", "text/html") w.Header().Set("Server", "Go 1.9.2 Server") w.Header().Set("Niubi", "hahahaha") var p *int *p = 10 //出现panic,go自动处理了异常,线程挂掉,但是进程不会挂掉 switch request.Method { case "GET": io.WriteString(w, form) case "POST": request.ParseForm() io.WriteString(w, request.FormValue("username")) io.WriteString(w, "\n") io.WriteString(w, request.FormValue("password")) }}func main() { http.HandleFunc("/test1", logPanics(SimpleServer) http.HandleFunc("/test2", logPanics(FormServer)) if err := http.ListenAndServe(":8088", nil); err != nil { }}func logPanics(handle http.HandlerFunc) http.HandlerFunc { return func(writer http.ResponseWriter, request *http.Request) { //返回匿名函数,原型和处理函数一致 defer func() { if x := recover(); x != nil { log.Printf("[%v] caught panic: %v", request.RemoteAddr, x) //捕获错误 } }() handle(writer, request) //执行处理函数 }}二、模板的使用
1、渲染到终端
模板文件index.html
{ { if gt .Age 18}} //gt大于, .指后端传过来的数据集hello, old man, {
{.Name}} { { else}}hello,young man, {
{.Name}} { {end}}
package mainimport ( "fmt" "os" "text/template" )type Person struct { Name string Age string}func main() { t, err := template.ParseFiles("./index.html") //加载模板 if err != nil { fmt.Println("parse file err:", err) return } p := Person{Name: "Mary", Age: "31"} if err := t.Execute(os.Stdout, p); err != nil{ fmt.Println("There was an error:", err.Error()) }}
2、渲染到前端
index2.html
hello, old man, {
{.age}}
package mainimport ( "fmt" "text/template" "net/http")type Person struct { Name string Age int}var ( gtemp *template.Template)func init() { t, err := template.ParseFiles("./index2.html") if err != nil { fmt.Println("parse file err:", err) return } gtemp = t}func handleUserInfo(w http.ResponseWriter, r *http.Request) { p := &Person{ Name:"mary", Age: 20, } //执行模板渲染 gtemp.Execute(w, p)}func main() { http.HandleFunc("/user_info", handleUserInfo) http.ListenAndServe(":8080", nil)}
三、模板语句
1)if判断
{ { if gt .Age 18}}hello, old man, {
{.Name}} { { else}}hello,young man, {
{.Name}} { {end}}
2)if常见操作符
not 非{ { if not .condition}} { {end}}and 与{ { if and .condition1 .condition2}} { {end}}or 或{ { if or .condition1 .condition2}}{ {end}}eq 等于{ { if eq .var1 .var2}}{ {end}}ne 不等于{ { if ne .var1 .var2}}{ {end}}lt 小于 (less than){ { if lt .var1 .var2}}{ {end}}le 小于等于{ { if le .var1 .var2}} { {end}}gt 大于{ { if gt .var1 .var2}}{ {end}}ge 大于等于{ { if ge .var1 .var2}}{ {end}}
3){ {.}}
后端传过来的结构体或者map,都是.xx提取数据
hello, old man, {
{.}}
4){ {with .Var}}
{ {with .Name}}hello, old man, {
{.}} //.代表Name的值 { {end}}
5)循环
{ {range .}} { { if gt .Age 18}}hello, old man, {
{.Name}} { { else}}hello,young man, {
{.Name}} { {end}} { {end}}
{ {.Name}} | { {.Age}} | { { else}}{ {.Name}} | { {.Age}} | { {end}}
package mainimport ( "fmt" "text/template" "net/http")type Person struct { Name string Age int}var ( gtemp *template.Template)func init() { t, err := template.ParseFiles("./index.html") if err != nil { fmt.Println("parse file err:", err) return } gtemp = t}func handleUserInfo(w http.ResponseWriter, r *http.Request) { var persons []*Person for i := 0; i < 10; i++{ p := &Person{ Name: fmt.Sprintf("stu%d", i), Age: i*10, } persons = append(persons, p) } //执行模板渲染 gtemp.Execute(w, persons)}func main() { http.HandleFunc("/user_info", handleUserInfo) http.ListenAndServe(":8080", nil)}
四、静态文件服务器
文件服务器
package mainimport ( "net/http")func main() { http.Handle("/", http.FileServer(http.Dir("./")) //http.Handle("/static/", http.FileServer(http.Dir("./static/"))) // '/static/'路径默认会加在./static/后面,需要将文件放在/static//static/下面 http.Handle("/media/", http.StripPrefix("/media/", http.FileServer(http.Dir("./media/")))) //去掉默认加在url /media/ http.ListenAndServe(":8080", nil)}
http模板渲染展示
package mainimport ( "fmt" "html/template" "net/http")var ( gtemp *template.Template)func init() { t, err := template.ParseFiles("./views/index.html") if err != nil { fmt.Println("parse file err:", err) return } gtemp = t}func handleIndex(w http.ResponseWriter, r *http.Request) { gtemp.Execute(w, nil)}func main() { http.HandleFunc("/index", handleIndex) //http.Handle("/static/", http.FileServer(http.Dir("./static/"))) // '/static/'路径默认会加在./static/后面,需要将文件放在/static//static/下面 http.Handle("/media/", http.StripPrefix("/media/", http.FileServer(http.Dir("./media/")))) //去掉默认加在url /media/ http.ListenAndServe(":8080", nil)}