代码编织梦想

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/

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/test1280/article/details/109597973

说一下http和https协议-爱代码爱编程

1、http协议和https协议 http协议:超文本传输协议,是互联网上应用最多的协议,基于TCP/IP通讯协议来传递信息,用于从WWW服务器传输超文本到本地浏览器的传输协议。 https协议:我们可以将其看作是以安全为目标的http协议。在http协议的基础上增加了SSL/TSL层,可以确保数据的传输的安全性和完整性。 在这里讲一下协议的组成

HTTP详解(4)之HTTPS详解一篇搞定-爱代码爱编程

文章目录 前言一、HTTP缺点二、HTTPS1.什么是HTTPS2.HTTPS组成2.HTTPS工作机制总结 前言 HTTPS我们经常用到,但对于HTTPS的机制和处理流程却没有深入思考,本文旨在对HTTPS的组成和工作方式进行一个简单的介绍和总结。下面先看一张总结图: 一、HTTP缺点 ●通信使用明文(不加密),内容

Request&Response-爱代码爱编程

Request&Response 今日目标 Request请求对象,获取 http请求消息格式(行、头、体)Response响应对象,设置 http响应消息格式(行、头、体) 第一章 Request概述 用户通过浏览器访问服务器时,Tomcat将HTTP请求中所有的信息都封装在Request对象中作用:开发人员可以通过r

TCP和UDP以及TCP的三次握手和四次挥手-爱代码爱编程

1、TCP和UDP Internet 的传输层有两个主要协议,互为补充。一个是TCP协议,一个是UDP协议。 UDP:用户数据报协议,是一种无连接的传输数据的协议。 TCP:传输控制协议,是一种面向连接的传输数据的协议。 2、TCP和UDP的区别 TCPUDP面向连接的无连接的面向字节流面向报文可靠的,数据能完整、不丢失的传输不可靠的,数据很容易在

常用完整Http请求返回状态码-爱代码爱编程

/** * 返回状态码 * * @author rcxc */ public class HttpStatus{ /** * 操作成功 */ public static final int SUCCESS = 200; /** * 对象创建成功 */ public stat

含着泪写完了这个Ruby - NetHTTP短信验证码接口,太不容易了-爱代码爱编程

成人的世界从来没有容易二字,生活如此,代码亦是如此,由于项目的需求,我写了一个Ruby - NetHTTP接入短信验证码接口的代码,没想到说我对接的接口的短信服务商价格太贵。 无可奈何,通过自己的聪明才智,终于在在各大云市场找到一个价格低且稳定的短信供应商~可把自己牛批坏了~ 下面就给大家分享我写的代码吧: require "uri" require

可支撑千万日活,这个Golang框架让你快速构建高并发微服务-爱代码爱编程

项目名称:go-zero 项目作者:kevwan 开源许可协议:MIT 项目地址:https://gitee.com/kevwan/go-zero   项目简介 go-zero 是一个集成了各种工程实践的 web 和 rpc 框架。通过弹性设计保障了大并发服务端的稳定性,经受了充分的实战检验。 go-zero 包含极简的 API 定义和生成工

golang testing-爱代码爱编程

概述 func TestXxx(*testing.T) 测试函数的名字,Test要以大写开始。 测试的文件名是 xxx_test.go, "_test.go"结尾,文件内是TestXxx的函数。文件放在被测试模块同一目录。 具体错误可以用testing.T的Errorf来输出。 Benchmarks func BenchmarkXxx(*tes

用 Go 手写一个 JSON 序列化器-爱代码爱编程

用 Go 手写一个 JSON 序列化器 方案实现字符串转义忽略类型序列化器主体数字和逻辑类型字符串类型数组类型字典类型自定义结构类型指针类型API使用安装调用测试开源和贡献 在处理 JSON 的时候,序列化是一个非常有用的功能,可以直接将对象转换为序列化后的 JSON。 一般来说,处理 JSON 的序列化时的步骤是递归遍历一个对象中的所有字段

gin 中间件 Next() 函数-爱代码爱编程

参考url: https://segmentfault.com/q/1010000020256918 调用Next函数会立刻自信后续的handler,反之,等本中间件执行完毕后,再执行后续的handler 立刻终止handler的执行和后续待执行的handler的执行的相关函数  参考url https://godoc.org/github.com/

一文搞懂gin各种上传文件-爱代码爱编程

一、先封装一个根据年月日时间方式来创建目录 1、创建一个utils的文件夹并且创建folder.go的文件 package utils import ( "os" "path/filepath" "time" ) //定义一个创建文件目录的方法 func Mkdir(basePath string) string { // 1.获取当前时间

goland 搭建 gin 框架-爱代码爱编程

1. 安装go软件包 下载地址:https://studygolang.com/dl 下载后,双击安装即可。 2. 配置系统变量 这里需要配置2个系统变量,一个是GOROOT,一个是GOPATH 注意:GOROOT和GOPATH不能在同一路径下,且变量名必须是GOROOT和GOPATH. 3. 安装git