go http

go http编程

  • Go原生支持http,import(“net/http”)
  • Go的http服务性能和nginx比较接近
  • 几行代码就可以实现一个web服务

1、http server

package main

import (
	"fmt"
	"net/http"
)

func Hello(w http.ResponseWriter, r *http.Request) {
	fmt.Println("handle hello")
	fmt.Fprintf(w, "hello ")
}

func login(w http.ResponseWriter, r *http.Request) {
	fmt.Println("handle login")
	fmt.Fprintf(w, "login ")
}

func history(w http.ResponseWriter, r *http.Request) {
	fmt.Println("handle history")
	fmt.Fprintf(w, "history ")
}

func main() {
	http.HandleFunc("/", Hello)
	http.HandleFunc("/user/login", login)
	http.HandleFunc("/user/history", history)
	err := http.ListenAndServe("0.0.0.0:8880", nil)
	if err != nil {
		fmt.Println("http listen failed")
	}
}

2、http client

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))
}

3、http常见请求方法

  • Get请求
  • Post请求
  • Put请求
  • Delete请求
  • Head请求

4、http 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)
		if err != nil {
			fmt.Printf("head %s failed, err:%v\n", v, err)
			continue
		}

		fmt.Printf("head succ, status:%v\n", resp.Status)
	}
}
  • 超时控制
package main

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

var url = []string{
	"http://www.baidu.com",
	"http://google.com",
	"http://taobao.com",
}

func main() {

	for _, v := range url {
		c := http.Client{
			Transport: &http.Transport {
				Dial:func(network, addr string) (net.Conn, error){
					timeout := time.Second*2
					return net.DialTimeout(network, addr, timeout)
				},
			},
		}
		resp, err := c.Head(v)
		if err != nil {
			fmt.Printf("head %s failed, err:%v\n", v, err)
			continue
		}

		fmt.Printf("head succ, status:%v\n", resp.Status)
	}
}

5、http 表单处理

package main
import (
	"io"
	"net/http"
)

const form = `<html><body><form action="#" method="post" name="bar">
                    <input type="text" name="in"/>
                    <input type="text" name="in"/>
                     <input type="submit" value="Submit"/>
             </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")
	switch request.Method {
	case "GET":
		io.WriteString(w, form)
	case "POST":
		request.ParseForm()
		io.WriteString(w, request.Form["in"][0])
		io.WriteString(w, "\n")
		io.WriteString(w, request.FormValue("in"))
	}
}
func main() {
	http.HandleFunc("/test1", SimpleServer)
	http.HandleFunc("/test2", FormServer)
	if err := http.ListenAndServe(":8088", nil); err != nil {
	}
}

6、panic处理

package main

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

const form = `<html><body><form action="#" method="post" name="bar">
                    <input type="text" name="in"/>
                    <input type="text" name="in"/>
                     <input type="submit" value="Submit"/>
             </form></body></html>`

func SimpleServer(w http.ResponseWriter, request *http.Request) {
	io.WriteString(w, "hello, world")
	panic("test test")
}

func FormServer(w http.ResponseWriter, request *http.Request) {
	w.Header().Set("Content-Type", "text/html")
	switch request.Method {
	case "GET":
		io.WriteString(w, form)
	case "POST":
		request.ParseForm()
		io.WriteString(w, request.Form["in"][1])
		io.WriteString(w, "\n")
		io.WriteString(w, request.FormValue("in"))
	}
}
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)
	}
}

 

http 模板

1、替换

main.go

package main

import (
	"fmt"
	"os"
	"text/template"
)

type Person struct {
	Name  string
	Title string
	age   string
}

func main() {
	t, err := template.ParseFiles("e:/wangjian/go/project/src/go_dev/day10/template/index.html")
	if err != nil {
		fmt.Println("parse file err:", err)
		return
	}
	p := Person{Name: "Mary", age: "31", Title: "我的个人网站"}
	if err := t.Execute(os.Stdout, p); err != nil {
		fmt.Println("There was an error:", err.Error())
	}
}

index.html

<html>
    <head>
        <title>{{.Title}}</title>
    </head>
    <body>
        <p> hello, {{.Name}}</p>
        <p> {{.}}</p>
    </body>
</html>

2、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>

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、{{.}}

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

4、{{with .Var}} {{end}}

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

5、循环{{range.}} {{end }}

<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>

样例

index.html

<html>
    <head>
        
    </head>
    <body>
        <p>hello world</p>
        <table border="1">
        {{range .}}
            <tr>
                <td>{{.Name}}</td> <td>{{.Age}}</td><td>{{.Title}}</td>
            </tr>
         {{end}}
        </table>
    </body>
</html>

main.go

package main

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

var myTemplate *template.Template

type Result struct {
	output string
}

func (p *Result) Write(b []byte) (n int, err error) {
	fmt.Println("called by template")
	p.output += string(b)
	return len(b), nil
}

type Person struct {
	Name  string
	Title string
	Age   int
}

func userInfo(w http.ResponseWriter, r *http.Request) {
	fmt.Println("handle hello")
	//fmt.Fprintf(w, "hello ")
	var arr []Person
	p := Person{Name: "Mary001", Age: 10, Title: "我的个人网站"}
	p1 := Person{Name: "Mary002", Age: 10, Title: "我的个人网站"}
	p2 := Person{Name: "Mary003", Age: 10, Title: "我的个人网站"}
	arr = append(arr, p)
	arr = append(arr, p1)
	arr = append(arr, p2)

	resultWriter := &Result{}
	io.WriteString(resultWriter, "hello world")
	err := myTemplate.Execute(w, arr)
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("template render data:", resultWriter.output)
	//myTemplate.Execute(w, p)
	//myTemplate.Execute(os.Stdout, p)
	//file, err := os.OpenFile("C:/test.log", os.O_CREATE|os.O_WRONLY, 0755)
	//if err != nil {
	//	fmt.Println("open failed err:", err)
	//	return
	//}

}

func initTemplate(filename string) (err error) {
	myTemplate, err = template.ParseFiles(filename)
	if err != nil {
		fmt.Println("parse file err:", err)
		return
	}
	return
}

func main() {
	initTemplate("e:/wangjian/go/project/src/go_dev/day10/template_http/index.html")
	http.HandleFunc("/user/info", userInfo)
	err := http.ListenAndServe("0.0.0.0:8880", nil)
	if err != nil {
		fmt.Println("http listen failed")
	}
}

 

参数介绍

 

const (
	MaxIdleConns int = 100
	MaxIdleConnsPerHost int = 100
	IdleConnTimeout int = 90
)

client := &http.Client{
		Transport: &http.Transport{
			DisableKeepAlives: true,
			Proxy: http.ProxyFromEnvironment,
			DialContext: (&net.Dialer{
				Timeout:   30 * time.Second,
				KeepAlive: 30 * time.Second,
			}).DialContext,
			MaxIdleConns:        MaxIdleConns,
			MaxIdleConnsPerHost: MaxIdleConnsPerHost,
			IdleConnTimeout:	 time.Duration(IdleConnTimeout)* time.Second,
		},
		Timeout: 15 * time.Second,
	}

 

  • DisableKeepAlives,表示是否开启http keepalive功能,也即是否重用连接,默认开启(false)
  • MaxIdleConns,表示连接池对所有host的最大链接数量,host也即dest-ip,默认为无穷大(0),但是通常情况下为了性能考虑都要严格限制该数目(实际使用中通常利用压测 二分得到该参数的最佳近似值)。太大容易导致客户端和服务端的socket数量剧增,导致内存吃满,文件描述符不足等问题;太小则限制了连接池的socket数量,资源利用率较低。
  • MaxIdleConnsPerHost,表示连接池对每个host的最大链接数量,从字面意思也可以看出:如果客户端只需要访问一个host,那么最好将MaxIdleConnsPerHostMaxIdleConns设置为相同,这样逻辑更加清晰。
  • IdleConnTimeout,空闲timeout设置,也即socket在该时间内没有交互则自动关闭连接(注意:该timeout起点是从每次空闲开始计时,若有交互则重置为0),该参数通常设置为分钟级别,例如:90秒。
  • DialContext,该函数用于创建http(非https)连接,通常需要关注TimeoutKeepAlive参数。前者表示建立Tcp链接超时时间;后者表示底层为了维持http keepalive状态 每隔多长时间发送Keep-Alive报文。Timeout通常设置为30s(网络环境良好),KeepAlive通常设置为30s(与IdleConnTimeout要对应)。

 

posted @ 2017-09-12 14:55  shhnwangjian  阅读(1393)  评论(0编辑  收藏  举报