http编程

一、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    //客户端能接收的mine
Accept-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    //主体内容长度    
//空行用来分割消息头和主体
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"... //消息体

发送http请求

package main

import (
    "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]))
    }
}
View Code

 

 

HTTP服务端

package main

import (
    "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 main

import (
    "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 main

import (
    "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)
    }
}
View Code

3.http 常见状态码

http.StatusContinue = 100   //继续访问
http.StatusOK = 200
http.StatusFound = 302        //跳转
http.StatusBadRequest = 400    //发送的请求,协议格式不对
http.StatusUnauthorized =401    //没有授权
http.StatusForbidden = 403        //没有权限访问
http.StatusNotFound = 404        //请求地址不存在
http.StatusInternalServerError = 500    //服务器有问题
502  //有代理,后端服务挂了
504  //后端处理请求超时

4、表单处理

package main

import (
    "io"
    "net/http"
)
const form =`<html><meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
            <body><form action="#" method="post" name="bar">
            <div> 姓名:<input type="text" name="username1"/></div>
            <div> 密码:<input type="text" name="password"/></div>
            <input type="submit" value="登录"/>
            </form></html></body>`
func SimpleServer(w http.ResponseWriter, request *http.Request) {
    io.WriteString(w, "<h1>hello, world</h1>")  //返回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 {
        
    }
}
View Code

5、panic处理

package main

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

const form = `<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
<body><form action="#" method="post" name="bar">
<div> 姓名:<input type="text" name="username1"/></div>
<div> 密码:<input type="text" name="password"/></div>
<input type="submit" value="登录"/>
</form></html></body>`

func SimpleServer(w http.ResponseWriter, request *http.Request) {
    io.WriteString(w, "<h1>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")

    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)  //执行处理函数
    }
}
View Code

二、模板的使用

1、渲染到终端

模板文件index.html

<html>
    <head>
    </head>
    <body>
        {{if gt .Age 18}}  //gt大于, .指后端传过来的数据集
            <p>hello, old man, {{.Name}}</p>
        {{else}}
            <p>hello,young man, {{.Name}}</p>
        {{end}}
    </body>
</html>

 

package main

import (
    "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

<html>
    <head>
    </head>
    <body>    
        <p>hello, old man, {{.age}}</p>  
    </body>
 </html>

 

package main

import (
    "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判断

<html>
    <head>
    </head>
    <body>
        {{if gt .Age 18}}
            <p>hello, old man, {{.Name}}</p>
        {{else}}
            <p>hello,young man, {{.Name}}</p>
        {{end}}
    </body>
</html>

2if常见操作符

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}}
View Code

3){{.}}

后端传过来的结构体或者map,都是.xx提取数据

<html>
    <head>
    </head>
    <body>
        <p>hello, old man, {{.}}</p>
    </body>
</html>

4){{with .Var}}

<html>
    <head>
    </head>
    <body>
        {{with .Name}}
            <p>hello, old man, {{.}}</p>   //.代表Name的值
        {{end}}
    </body>

</html>

5)循环

<html>
    <head>
    </head>
    <body>
        {{range .}}
            {{if gt .Age 18}}
                <p>hello, old man, {{.Name}}</p>
            {{else}}
                <p>hello,young man, {{.Name}}</p>
            {{end}}
        {{end}}
    </body>
</html>

 

<html>
<head>
</head>
<body>
<table border="1px">
{{range .}}
    <tr>
    {{if gt .Age 18}}
    <td> {{.Name}}</td>
    <td> {{.Age}}</td>       
    {{else}}
    <td> {{.Name}}</td>
    <td> {{.Age}}</td>       
    {{end}}
    </tr>
{{end}}
</table>
</body>
</html>
index.html
package main

import (
    "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)
}
main.go


四、静态文件服务器

文件服务器

package main

import (    
    "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 main

import (
    "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)
}
mian.go

 

posted @ 2018-02-12 09:41  shy车队破风手  阅读(749)  评论(0编辑  收藏  举报