go語言 http學習
阿新 • • 發佈:2018-06-18
get ram stax serve config lan asi html text
net/http庫學習
概念
處理器
處理器:擁有ServeHTTP方法的接口(任何類型)
簽名:ServeHTTP(http.ResponseWriter, *http.Request)
- ResponseWriter接口
- 指向Request結構的指針
- ServeMux結構(擁有ServeHTTP方法,如上簽名)
- Handler結構
- 多路復用器 DefaultServeMux(ServeMux結構的實例)
處理器函數
- 與處理器有相同行為的函數
- 與ServeHTTP方法有相同的簽名
ServeMux
- HTTP請求多路復用器
- __接收HTTP請求__並根據請求中的__URL__將請求重定向到正確的處理器
- __接收HTTP請求__並根據請求中的__URL__將請求重定向到正確的處理器
- ServeMux結構也實現了ServeHTTP方法,它也是一個處理器
- ServeMux的ServeHTTP方法,調用與被請求URL相對應的__處理器__的ServeHTTP方法
最簡單的Web服務器
import "fmt" import "net/http" // 處理器 type HelloHandler struct{} func ( h *HelloHandler) ServeHTTP ( w http.ResponseWriter, r * http.Request){ fmt.Fprintf( w, "Hello" ) } // 處理器函數 func hello( w http.ResponseWriter, r * http.Request){ fmt.Fprintf( w, "Hello" ) } func main () { server := http.Server{ Addr: "127.0.0.1:8080", //Handler: nil, //可以指定處理器 } fmt.Println("hello https://tool.lu/") //http.ListenAndServe(":8181", nil) //server.ListenAndServe() // 將 處理器 綁定到DefaultServeMux // Handle是ServeMux結構的方法,而DefaultServeMux是ServeMux的實例 //hello := HelloHandler{} //http.Handle("/hello", &hello) // 將函數轉換為處理器,再將處理器綁定到DefaultServeMux //http.HandleFunc( "/hello", hello ) //使用默認的多路復用器DefaultServeMux作為處理器 server.ListenAndServeTLS("cert.pem", "key.pem") }
http客戶端
http.NewRequest
- htp.Client -> http.request(http.NewRequest) -> client.Do(request)
- NewRequest(method, urlStr string, body io.Reader)
- 第三個參數是請求的body中的內容
- request.Header.Set
- 向請求首部添加信息
http.Clinet
- cient結構api
- client.get/post/postform
- client參數配置
- Transport RoundTripper
- CheckRedirect func(req Request, via []
- Jar CookieJar
- Timeout time.Duration
- Transport
- 為了控制代理、安全套接層設置、保持連接、壓縮、超時設置和其它設定,需要創建一個Transport
- MaxIdleConns
- 對所有host的最大連接數量
- MaxIdleConnsPerHost
- 對__每個host__的最大連接數量
tr := &http.Transport{
TLSClientConfig: &tls.Config{RootCAs: pool},
DisableCompression: true,
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://example.com")
tr := &http.Transport{
MaxIdleConnsPerHost: 1000, //是否表示最多建立1000個連接?
}
client := &http.Client{
Transport: tr,
}
http
- http.Get/Post/Postform
resp.Body.Close()
- 當客戶端使用完response body後必須使用close對其進行關閉
httplib學習
https://github.com/astaxie/beego
概念
- httplib庫主要用來模擬客戶端發送HTTP請求
- 類似於curl工具
使用
- request對象
- debug輸出
- 設置clinet的TLS信息
gin學習
package tests
import (
"encoding/json"
"fmt"
"github.com/astaxie/beego/httplib"
"github.com/gin-gonic/gin"
"io/ioutil"
"log"
"net/http"
"strings"
"testing"
"time"
)
func handleTestGet(c *gin.Context) {
c.String(http.StatusOK, "test get OK")
}
func handleTestPost(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"code": 1, "message": "test post OK"})
}
func handleParam(c *gin.Context) {
name := c.Param("name")
passwd := c.Param("passwd")
c.String(http.StatusOK, "name: %s, passwd: %s", name, passwd)
}
func handleQuery(c *gin.Context) {
name := c.Query("name")
passwd := c.Query("passwd")
c.String(http.StatusOK, "name: %s, passwd: %s", name, passwd)
}
func handleHTTPLib(c *gin.Context) {
c.IndentedJSON(200, gin.H{"code": 1, "data": "ok"})
}
func runtBasicGinServer() {
fmt.Print("aa")
router := gin.Default()
router.GET("/test_get", handleTestGet)
router.POST("/test_post", handleTestPost)
router.GET("/test_param/:name/*passwd", handleParam)
router.GET("/test_query", handleQuery)
router.GET("/test_httplib", handleHTTPLib)
group := router.Group("/v1")
group.GET("/test_group", handleTestGet)
router.Run(":6543")
}
func printGetResp(resp *http.Response) {
defer resp.Body.Close()
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Printf("read body err %s\n", err.Error())
}
log.Printf("resp body is: %+v\n", string(bodyBytes))
}
func printPostResp(resp *http.Response) {
defer resp.Body.Close()
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Printf("read body err %s\n", err.Error())
}
type body struct {
Code int `json:"code"`
Message string `json:"message"`
}
respBody := body{}
err = json.Unmarshal(bodyBytes, &respBody)
if err != nil {
log.Printf("unmarshal body err %s\n", err.Error())
}
log.Printf("resp body is: %+v\n", respBody)
}
func TestBasicClient(t *testing.T) {
go runtBasicGinServer()
time.Sleep(time.Second * 5)
resp, err := http.Get("http://127.0.0.1:6543/test_get")
if err != nil {
log.Printf("get resp err %s\n", err.Error())
}
printGetResp(resp)
resp, err = http.Post("http://127.0.0.1:6543/test_post", "", strings.NewReader(""))
if err != nil {
log.Printf("get resp err %s\n", err.Error())
}
printPostResp(resp)
resp, err = http.Get("http://127.0.0.1:6543/test_param/name=Bob/passwd=1234")
if err != nil {
log.Printf("get resp err %s\n", err.Error())
}
printGetResp(resp)
resp, err = http.Get("http://127.0.0.1:6543/test_param/name=Bob/")
if err != nil {
log.Printf("get resp err %s\n", err.Error())
}
printGetResp(resp)
resp, err = http.Get("http://127.0.0.1:6543/test_param/name=Bob")
if err != nil {
log.Printf("get resp err %s\n", err.Error())
}
printGetResp(resp)
resp, err = http.Get("http://127.0.0.1:6543/test_query?name=Alice&passwd=123")
if err != nil {
log.Printf("get resp err %s\n", err.Error())
}
printGetResp(resp)
resp, err = http.Get("http://127.0.0.1:6543/v1/test_group")
if err != nil {
log.Printf("get resp err %s\n", err.Error())
}
printGetResp(resp)
res := struct {
Code int `json:"code"`
Message string `json:"message"`
}{}
if err := httplib.Get("http://127.0.0.1:6543/test_httplib").ToJSON(&res); err != nil {
log.Println(err.Error())
}
log.Printf("%+v", res)
}
func TestReuseHTTPLink(t *testing.T) {
go runtBasicGinServer()
time.Sleep(time.Second * 5)
tr := &http.Transport{
MaxIdleConnsPerHost: 100,
MaxIdleConns: 100,
}
c := http.Client{Transport: tr}
url := "http://127.0.0.1:6543/test_get"
/*
連接數,
當前 無剩余 可用連接時 會創建;
當前 有剩余 可用連接則 不創建
*/
// use channel to control http port numbers
ch := make(chan struct{}, 100)
for i := 0; i < 5000; i++ {
go func(i int) {
ch <- struct{}{}
defer func() {
<-ch
}()
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Printf("get req error %s", err.Error())
}
resp, err := c.Do(req)
if err != nil {
log.Printf("do req error %s", err.Error())
}
defer resp.Body.Close()
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Printf("read body error %s", err.Error())
}
log.Printf("%d body: %s", i, string(bodyBytes))
}(i)
//time.Sleep(time.Microsecond * 50)
//time.Sleep(time.Microsecond * 50)
}
time.Sleep(time.Second * 10)
}
func TestSeqDo(t *testing.T) {
go runtBasicGinServer()
time.Sleep(time.Second * 5)
c := http.Client{}
url := "http://127.0.0.1:6543/test_get"
/*
defaul reuse http link
there is one link to 6543
*/
for i := 0; i < 5000; i++ {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
log.Printf("get req error %s", err.Error())
}
resp, err := c.Do(req)
if err != nil {
log.Printf("do req error %s", err.Error())
}
defer resp.Body.Close()
bodyBytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Printf("read body error %s", err.Error())
}
log.Printf("%d body: %s", i, string(bodyBytes))
}
time.Sleep(time.Second * 10)
}
func TestSeqHTTPLib(t *testing.T) {
go runtBasicGinServer()
time.Sleep(time.Second * 5)
url := "http://127.0.0.1:6543/test_get"
/*
???netstat -anp | grep 6543 | grep ESTABLISHED
*/
for i := 0; i < 5000; i++ {
bodyString, err := httplib.Get(url).String()
if err != nil {
log.Printf("httplib get error %s", err.Error())
}
log.Printf("%d body: %s", i, bodyString)
}
time.Sleep(time.Second * 10)
}
binding學習
github.com/gin-gonic/gin/binding
HTTPS服務
參考文獻
《Go Web 編程》
Go語言_HTTP包
深入Go語言網絡庫的基礎實現
golang中發送http請求的幾種常見情況
Go語言net/http 解讀
go net/http Client使用——長連接客戶端的使用
https://github.com/astaxie/beego
beego中文文檔
go語言 http學習