创建简单的服务端
1、创建HTTP服务端
要创建一个Go语言的HTTP服务器端,需先使用HandleFunc()函数注册路由,然后通过ListenAndServe()函数开启对客户端的监听。
func main() {
http.HandleFunc("/hello", SayHello)
http.ListenAndServe(":8080", nil)
}
func SayHello(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("hello"))
}
内部调用逻辑分析:
这里简要分析一下Go语言net/http包的内部调用逻辑。如果要创建一个Web服务器端,则需要:①调用http.HandleFunc()函数;②调用htp.ListenAndServe()函数。
ListenAndServe()函数有两个参数:当前监听的端口号和事件处理器handler。
在Go语言中,Handler接口的定义如下:
type Handler interface {
ServeHTTP (ResponseWriter,*Request)
}
只需要实现了这个接口,就可以实现自己的handler处理器。Go语言在net/http包中已经提供了实现这个接口的公共方法:
type HandlerFunc func(ResponseWriter,*Request)
func (f HandlerFunc)ServeHTTP(w ResponseWriter,r *Request){
f(w,r)
}
handler处理器的机制类似于Java SpringMVC框架中的Interceptor,是一个拦截器。它发生在http.HandleFunc()函数处理逻辑之前。
ServeHTTP()方法的使用示例:
例如要实现一个功能:在发送HTTP请求时,只有带上指定的refer参数,该请求才能调用成功,否则返回403状态。示例如下。
/*
实现一个功能:在发送HTTP请求时,只有带上指定的refer参数,该请求才能
调用成功,否则返回403状态
*/
func main() {
referer := &Refer{
handler: http.HandlerFunc(myHandler),
refer: "www.shirdon.com",
}
http.HandleFunc("/hello", hello1)
http.ListenAndServe(":8080", referer)
}
type Refer struct {
handler http.Handler
refer string
}
func (this *Refer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Referer() == this.refer {
this.handler.ServeHTTP(w, r)
} else {
w.WriteHeader(403)
}
}
func myHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("this is handler"))
}
func hello1(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello"))
}
2、创建HTTPS服务端
在Go语言中使用HTTPS的方法很简单,net/http包,中提供了启动HTTPS服务的方法,其定义如下:
func (srv *Server)ListenAndServeTLS(certFile,keyFile string)
error
通过方法可知,只需要两个参数就可以实现HTTPS服务。这两个参数分别是证书文件的路径和私钥文件的路径。要获取这两个文件,通常需要从证书颁发机构获取。虽然有免费的,但还是比较麻烦,通常还需要购买域名及申请流程。
为了简单起见,我们直接使用自己创建的签名证书。注意,这样的证书是不会被浏览器信任的。
Go语言的net/htp包默认支持HTTP2。在1.6以上的版本中,如果使用HTTPS模式启动服务器,则服务器默认使用HTTP2。使用方法如下。
创建一个私钥和一个证书:
在Liux系统中,打开命令行终端输入下面的命令:
openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 365 -out server.crt
该命令将生成两个文件:server.key和server.crt。
/*
创建一个简单的HTTPS服务器端
*/
func main() {
//启动服务器
srv := &http.Server{
Addr: ":8080",
Handler: http.HandlerFunc(handle),
}
//用TLS启动服务器,因为运行的是HTTP2,所以它必须与TLS一起运行
log.Printf("Serving on https://0.0.0.0:8080")
log.Fatal(srv.ListenAndServeTLS("server.crt", "server.key"))
}
func handle(w http.ResponseWriter, r *http.Request) {
//记录请求协议
log.Printf("Got connection: %s", r.Proto)
//想客户端发送一条消息
w.Write([]byte("hello this is a HTTP 2 message!"))
}
创建简单的客户端
在net/http包中还提供了一个被称为Client的结构体。该结构体位于库文件src/net/http/client.go中,并且还提供了一个默认的变量可直接使用:
var Defaultclient &client(}
Client:结构体实现了Get()、Post()两个请求函数。这两个函数的定义如下:
func Get(url string)(resp *Response,err error)
func Post(url,contentType string,body io.Reader)
查看源码可以发现,net/http包的Get)函数实现如下:
func Get(url string)(resp *Response,err error){
return Defaultclient.Get (url)
}
在上面的Get()函数中,使用了DefaultClient对象的Get()方法。该Get()方法的具体实现代码如下:
func (c *client)Get(url string)(resp *Response,err error){
req,err:=NewRequest ("GET",url,nil)
if err != nil {
return nil,err
}
return c.Do(req)
}
同样,net/http包的Post()函数的具体实现代码如下:
func Post(url string, contentType string, body io.Reader) (resp *Response, err error) {
return DefaultClient.Post(url, contentType, body)
}
func (c *Client) Post(url string, contentType string, body io.Reader) (resp *Response, err error) {
req, err := NewRequest("POST", url, body)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", contentType)
return c.Do(req)
}
Get()、Post()函数的本质是,Go程序在底层传递相应的参数去调用NewRequest()函数。所以,在Go语言中创建客户端,最核心的HTTP请求方法就是NewRequest()函数。因为PUT、DELETE方法在Go语言中没有被单独封装,所以只能通过直接调用NewRequest()函数来实现。
GET请求
func main() {
resp, err := http.Get("https://www.baidu.com")
if err != nil {
fmt.Print("err", err)
}
closer := resp.Body
bytes, err := ioutil.ReadAll(closer)
fmt.Println(string(bytes))
}
POST请求
func main() {
url := "https://www.shirdon.com/comment/add"
body := "{\"userId\":1,\"articleId\":1,\"comment\":\"这是一条评论\"}"
response, err := http.Post(url, "application/x-www-form-urlencoded", bytes.NewBuffer([]byte(body)))
if err != nil {
fmt.Println("err", err)
}
b, err := ioutil.ReadAll(response.Body)
fmt.Println(string(b))
}
PUT请求
func main() {
url := "https://www.shirdon.com/comment/update"
payload := strings.NewReader("{\"userId\":1, \"articleId\":1,\"comment\":\"这是一条评论\"}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
DELETE请求
func main() {
url := "https://www.shirdon.com/comment/update"
payload := strings.NewReader("{\"userId\":1, \"articleId\":1,\"comment\":\"这是一条评论\"}")
req, _ := http.NewRequest("DELETE", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
设置请求头
//请求头设置
header := http.Header{"token": {"dhfsklsdfdksfddslieccssef3243dlsdc"}}
header.Add("Accept-Charset", "UTF-8")
header.Set("Host", "www.shirdon.com")