GO:HTTP客户端和服务端demo

43 篇文章 3 订阅
30 篇文章 1 订阅

GO:HTTP客户端和服务端demo

客户端:
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

func main() {

	/* 示例1:GET */
	{
		fmt.Println("+++++++++++++++++++++++++++++++++++++++++++++")

		/* 发请求收应答 */
		ack, err := http.Get("http://127.0.0.1:1280/")
		if err != nil {
			panic(err)
		}

		/* 读取应答正文 */
		ackBody, err := ioutil.ReadAll(ack.Body)
		/* 关闭应答正文,释放资源,无论是否异常 */
		ack.Body.Close()
		if err != nil {
			panic(err)
		}

		/* 输出应答状态 */
		fmt.Printf("HTTP Response StatusCode: %d\n", ack.StatusCode)
		fmt.Printf("HTTP Response Status: %s\n", ack.Status)

		/* 输出应答头域 */
		fmt.Printf("HTTP Response HEADER: %s\n", ack.Header.Get("my-http-head"))

		/* 输出应答正文 */
		fmt.Printf("HTTP Response BODY: %s\n", ackBody)
	}

	/* 示例2:POST */
	{
		fmt.Println("---------------------------------------------")

		/* 构建请求正文 */
		reqBody := strings.NewReader(`
			{
				"name": "test1280"
			}
		`)

		/* 创建请求对象 */
		req, err := http.NewRequest("POST", "http://127.0.0.1:1281/", reqBody)
		if err != nil {
			panic(err)
		}

		/* 设置请求头域 */
		req.Header.Set("Content-Type", "application/json")

		/* 发请求收应答 */
		ack, err := http.DefaultClient.Do(req)
		if err != nil {
			panic(err)
		}

		/* 读取应答正文 */
		ackBody, err := ioutil.ReadAll(ack.Body)
		/* 关闭应答正文,释放资源,无论是否异常 */
		ack.Body.Close()
		if err != nil {
			panic(err)
		}

		/* 输出应答状态 */
		fmt.Printf("HTTP Response StatusCode: %d\n", ack.StatusCode)
		fmt.Printf("HTTP Response Status: %s\n", ack.Status)

		/* 输出应答头域 */
		fmt.Printf("HTTP Response HEADER: %s\n", ack.Header.Get("my-http-head"))

		/* 输出应答正文 */
		fmt.Printf("HTTP Response BODY: %s\n", ackBody)
	}
}
服务端:
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"time"
)

func main() {
	/* 监听一个端口方式 */
	go func() {
		/* 使用http.DefaultServeMux */
		http.HandleFunc("/", handle)
		http.ListenAndServe(":1280", nil)
	}()

	/* 监听多个端口方式 */
	go func() {
		/* 自定义ServeMux */
		mux := http.NewServeMux()
		mux.HandleFunc("/", handle)
		http.ListenAndServe(":1281", mux)
	}()

	/* 测试代码,保证主线程/协程不退出 */
	time.Sleep(time.Second*60*10)
}

func handle(w http.ResponseWriter, r *http.Request) {

	/* 读取发请求客户端地址 */
	fmt.Printf("Receive HTTP REQ FROM: %s\n", r.RemoteAddr)
	/* 读取请求方法 */
	fmt.Printf("Method: %s\n", r.Method)
	/* 读取请求URL */
	fmt.Printf("URL: %s\n", r.URL)

	/* 读取请求头域 */
	// key and values
	for k, vs := range r.Header {
		for _, v := range vs {
			fmt.Printf("HTTP HEADER: %s\t\t:%s\n", k, v)
		}
	}

	/* 读取请求正文 */
	reqBody, err := ioutil.ReadAll(r.Body)
	if err != nil {
		panic(err)
	}
	/* 输出请求正文 */
	fmt.Printf("HTTP REQ BODY:\n%s\n", reqBody)
	/* 不需要显式关闭http.Request.Body */

	/* 设置HTTP应答头 */
	w.Header().Set("my-http-head", fmt.Sprintf("HTTP-REQ-METHOD-%s", r.Method))

	/* 生成应答正文 */
	ackBody, err := json.Marshal(r.Header)
	if err != nil {
		panic(err)
	}
	/* 设置应答状态 */
	w.WriteHeader(201)
	/* 设置应答正文 */
	w.Write(ackBody)
}
运行服务端:
test1280>go run http_server.go 
Receive HTTP REQ FROM: 127.0.0.1:55078
Method: GET
URL: /
HTTP HEADER: User-Agent		:Go-http-client/1.1
HTTP HEADER: Accept-Encoding		:gzip
HTTP REQ BODY:

Receive HTTP REQ FROM: 127.0.0.1:35026
Method: POST
URL: /
HTTP HEADER: Content-Length		:36
HTTP HEADER: Content-Type		:application/json
HTTP HEADER: Accept-Encoding		:gzip
HTTP HEADER: User-Agent		:Go-http-client/1.1
HTTP REQ BODY:

			{
				"name": "test1280"
			}
		
^Csignal: interrupt
运行客户端:
test1280>go run http_client.go 
+++++++++++++++++++++++++++++++++++++++++++++
HTTP Response StatusCode: 201
HTTP Response Status: 201 Created
HTTP Response HEADER: HTTP-REQ-METHOD-GET
HTTP Response BODY: {"Accept-Encoding":["gzip"],"User-Agent":["Go-http-client/1.1"]}
---------------------------------------------
HTTP Response StatusCode: 201
HTTP Response Status: 201 Created
HTTP Response HEADER: HTTP-REQ-METHOD-POST
HTTP Response BODY: {"Accept-Encoding":["gzip"],"Content-Length":["36"],"Content-Type":["application/json"],"User-Agent":["Go-http-client/1.1"]}

go官网给的样例很不错:

https://golang.org/pkg/net/http/#example_Get

package main

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

func main() {
	res, err := http.Get("http://www.google.com/robots.txt")
	if err != nil {
		log.Fatal(err)
	}
	robots, err := ioutil.ReadAll(res.Body)
	res.Body.Close()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", robots)
}

以前我常会写为:

	robots, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()

但是这样写存在问题:

1.如果不用“某个资源”,就应该尽可能快地释放它。

res.Body,就是一个“资源”,会占用内存等有限的系统资源。

如果确保后续代码中不使用它,那么不要使用defer延迟调用释放,而应该立刻调用释放其占用的资源。

2.错误时也应当关闭。

ioutil.ReadAll和res.Body是否关闭没有啥关系。

不应该在ioutil.ReadAll错误时,放任res.Body不关闭、不释放它。

读取完之后,立刻关闭释放,无论是否读取异常。


参考:

1.https://golang.org/pkg/net/http/#example_Get
2.https://ganlvtech.github.io/2018/12/08/go-http-server-demo/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值