Go Web编程.基础入门
Posted qq_51102350
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go Web编程.基础入门相关的知识,希望对你有一定的参考价值。
Go Web
一,反射
反射:计算机在运行时,可以访问,检测和修改它本身状态或行为的一种能力。
reflect包中定义了:
refelect.Type接口:提供类型相关信息
函数定义:
func TypeOf(i interface{}) Type
reflect.Value结构体:可以提供并改变值相关信息
函数定义:
func ValueOf(i interface{}) Value
根据reflect.Value类型的变量,可以使用Interface()方法使其恢复到其接口类型的值
func (v value) Interface() interface{}
基本用法一:
package main
import (
"fmt"
"reflect"
)
func main() {
x := 3.14
fmt.Println("type:", reflect.TypeOf(x))
fmt.Println("value", reflect.ValueOf(x))
v := reflect.ValueOf(x)
fmt.Println("type:", v.Type())
fmt.Println("kind is float64:", v.Kind() == reflect.Float64)
//Value类型提供了Int(),Float()等方法,可以让我们获取存在里面的值
fmt.Println("value", v.Float())
t := reflect.TypeOf(x)
fmt.Println("v", reflect.TypeOf(v))
fmt.Println("t", reflect.TypeOf(t))
//从反射对象到接口变量
i := v.Interface()
fmt.Println("i:", reflect.TypeOf(i), reflect.ValueOf(i))
}
修改“反射类型对象”:
使用reflect.TypeOf()函数和reflect.ValueOf()函数时,若传递的不是接口变量的指针,则传递的只是一个复制体
注意:
- 使用CanSet()方法来确定可写性
- 使用Elem()方法返回指针指向的数据
一些用于修改值的方法的定义:
func (v Value) SetBool(x bool)
func (v Value) SetBytes(x []byte)
func (v Value) SetFloat(x float64)
func (v Value) SetInt(x int64)
func (v Value) SetString(x string)
实例:
package main
import (
"fmt"
"reflect"
)
func main() {
name := "Go Web Program"
fmt.Println(name)
v1 := reflect.ValueOf(&name)
v2 := v1.Elem()
if v2.CanSet() {
v2.SetString("hhhhhh")
fmt.Println(name)
}
}
二,Hello World
1,服务器端创建
如果想要创建一个Web服务器端,则需要:
- 调用http.HandleFunc()
- 调用http.ListenAndServe()
ListenAndServe()函数有两个参数:当前监听的端口号addr和事件处理器handler
Handler接口的定义:
type Handler interface {
ServeHTTP(ResponseWirter, *Request)
}
只要实现了该接口,就可以实现自己的handler处理器
HandlerFunc()就是一个这样的处理器:
type HandlerFunc func(ResponseWriter, *Request)
func (f HAndlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
package main
import "net/http"
func SayHello(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("Hello"))
}
func main() {
http.HandleFunc("/hello", SayHello)
http.ListenAndServe(":8080", nil)
}
补充:
2,HTTPS服务器端
net/http包中提供的启动HTTPS服务的方法:
func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error
certfile:证书文件路径
keyFile:私钥文件路径
创建certifile和keyfile的命令行模板:
$ openssl req -newkey rsa:2048 -nodes -keyout 证书文件名称 -x509 -days 365 -out 私钥文件名称
package main
import (
"log"
"net/http"
)
func handle(w http.ResponseWriter, r *http.Request) {
//记录请求协议
log.Printf("Got connection: %s", r.Proto)
//向客户端发送信息
w.Write([]byte("233333333"))
}
func main() {
//启动服务器
serve := &http.Server{Addr: ":8080", Handler: http.HandlerFunc(handle)}
//用TLS启动服务器
log.Printf("Serving on https://0.0.0.0:8080")
log.Fatal(serve.ListenAndServeTLS("server.crt", "server.key"))
}
3,创建简单客户端
Ⅰ,基础知识
在net/http包中提供了一个名为Client的结构体
包含一个默认变量:
var DefaultClient = &Client{}
//net/http包包含的Get()函数
func Get(url string) (resp *Response, err error){
//注意到这里调用了Client的Get()方法
return DefaultClient.Get(url)
}
//Client的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 Get(url, contentType string,body io.Reader) (resp *Response, err error){
//注意到这里调用了Client的Post()方法
return DefaultClient.Post(url, contentType, body)
}
func (c *Client) Post(url, 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)
//用于关闭NewRequest返回的Request
return c.Do(req)
//NewRequest()是一个通用函数
func NewRequest(method, url string, body ,io.Reader) (*Request, error)
//method是参数请求类型,包括“GET” "POST"等
contentType:请求类型
io.Reader:一个接口
type Reader interface {
Read(p []byte) (n int, err error)
}
实现了Read方法的都是一个io.Reader
常见的有:
- strings.Reader
- bytes.Reader
- bytes.Buffer
- bufio.Reader
Ⅱ,创建GET请求
关于io/ioutil包
io/ioutil
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
resp, err := http.Get("https://www.baidu.com/")
if err != nil {
fmt.Println("err", err)
}
//将html内容赋给closer
result := resp.Body
bytes, err := ioutil.ReadAll(result)
fmt.Println(string(bytes))
}
Ⅲ,创建POST请求
关于strings包:
strings
首先创建一个接收application/json类型的请求的服务端:
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func postHandler(w http.ResponseWriter,r *http.Request){
defer r.Body.Close()
//请求类型是application/json时从r.Body读取数据
resp,err := ioutil.ReadAll(r.Body)
if err != nil{
fmt.Println("hhhhhh")
return
}
fmt.Println(string(resp))
answer := `{"status": "ok"}`
laugh := []byte("\\nhhhhh")
w.Write([]byte(answer))
w.Write(laugh)
}
func main(){
serve := &http.Server{Addr: ":2021",Handler: http.HandlerFunc(postHandler)}
serve.ListenAndServe()
}
发出post请求:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
)
// net/http post demo
func main() {
url := "http://127.0.0.1:2021"
//使用json的方式请求
contentType := "application/json"
data := `{"name":"hwc","age":19}`
resp, err := http.Post(url,contentType,strings.NewReader(data))
if err != nil{
fmt.Println("so sad it is")
}
result, err := ioutil.ReadAll(resp.Body)
if err != nil{
fmt.Println("so sad it is")
}
fmt.Println(string(result))
}
添加headers:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"strings"
)
// net/http post demo
func main() {
client := &http.Client{}
url := "http://127.0.0.1:2021"
useragent := "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0"
//使用json的方式请求
contentType := "application/json"
data := `{"name":"hwc","age":19}`
req, err := http.NewRequest("POST",url,strings.NewReader(data))
if err != nil{
fmt.Println("it is all too late")
}
//添加headers
req.Header.Add("Content-Type",contentType)
req.Header.Add("User-Agent",useragent)
resp,err := client.Do(req)
if err != nil{
fmt.Println("so sad it is")
}
result, err := ioutil.ReadAll(resp.Body)
if err != nil{
fmt.Println("so sad it is")
}
fmt.Println(string(result))
}
4,html/template包
该包实现了数据驱动的模板,Go语言中输出html的情景应使用这个包
动态网页:网页的布局和样式大致一样,但展示的内容不一样的网页
在一些前后段不分离的web架构中,我们需要在后端将一些数据渲染到HTML文档中,从而实现动态网页的效果。
模板的渲染机制可以理解为用文本替换操作:用数据取替换事先准备好的HTML模板中的标记
该包的作用机制:
- 模板文件通常为.tmpl和.tpl后缀,必须使用UTF-8编码
- 模板文件使用{{和}}包裹/标识需要传入的数据
- 模板文件中除了{{}}包裹的内容,其它内容都不做修改原样输出
模板引擎的使用:
- 定义模板文件,通俗点说,写一个html文件
- 解析模板文件
html/template提供了以下方法来解析模板文件,获得模板对象
//下面是这些方法的定义
//创建模板对象,添加模板名称
func New(name string) *Template
//创建模板对象,解析模板内容
func (t *Template) Parse(sec string) (*Template, error)
//解析模板文件,返回模板对象
func ParseFiles(filenames ...string) (*Template, error)
//批量解析文件
func ParseGlob(pattern string) (*Template, error)
//可使用该函数来进行正则匹配
- 渲染模板文件
func (t *Template) Execute(wr io.Writer, data interface{}) error {}
func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {}
注意:使用ParseFiles()函数可以一次加载多个模板,此时只能使用ExecuteTemplate()方法指定模板名称来执行数据融合
例:
tmpl文件:
<!DOCTYPE html>
<html>
<head>
<meta charset = "utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>life at age 19</title>
</head>
<body>
<h1>Foreign Time</h1>
<p>but i'm too young too late too young to find what I've been looking for</p>
<p>today is {{.DayTime}}</p>
<p>my emotion is {{.Emotion}}</p>
<p>{{.Log}}</p>
</body>
</html>
模板语法都包含在{{}}之间,其中{{.}}的点表示当前对象
传入结构体时,可依据“."来访问结构体的对应字段
.go文件:
package main
import (
"fmt"
"html/template"
"net/http"
)
type dayLog struct {
DayTime string
Emotion string
Log string
}
func testHandleFunc(w http.ResponseWriter,r *http.Request){
//1,parse template
tpl, err := template.ParseFiles("./test.tmpl")
if err != nil{
fmt.Println("sth wrong",err)
}
//2,execute template
var dayLog1 dayLog
dayLog1.DayTime = "2021.6.20"
dayLog1.Emotion = "a little blue"
dayLog1.Log = "universities painted life that has come before me"
err = tpl.Execute(w,dayLog1)
if err != nil{
fmt.Println("hhhh",err)
}
}
func main(){
serve := &http.Server{Addr: ":2021",Handler: http.HandlerFunc(testHandleFunc)}
serve.ListenAndServe()
}
三,接收处理Go Web请求
1,接收请求
Ⅰ,ServeMux和DefaultServeMux
ServeMux:一个结构体,可以找出与被请求URL最为匹配的URL,然后调用与之相应的处理器的ServeHTTP()方法来处理请求。
DefaultServeMux:ServeMux的一个实例。服务器默认使用DefaultServeMux来作为ServeMux结构体的实例。
HandleFunc()函数用于为指定URL注册一个处理器。会在内部调用DefaultServeMux对象的对应方法。
http.HandleFunc()函数将处理器注册到多路复用器中,多路复用器可以指定多个处理器。
定义:
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
实例:
package main
import "net/http"
type handler1 struct {}
type handler2 struct {}
func (h1 *handler1) ServeHTTP(w http.ResponseWriter,r *http.Request){
w.Write([]byte("hi,handler1"))
}
func (h2 *handler2) ServeHTTP(w http.ResponseWriter,r *http.Request){
w.Write([]byte("hi,handler2"))
}
func main(){
h1 := handler1{}
h2 := handler2{}
server := http.Server{
Addr: ":8085",
Handler: nil,//nil表明服务器使用默认多路复用器DefaultServeMux
}
//Handle()函数调用的是多路复用器DefaultServeMux.Handle()方法
//Handle()函数用于指定多个处理器
http.Handle("/handle1",&h1)
http.Handle("/handle2",&h2)
server.ListenAndServe()
}
默认的多路复用气功在实际生产环境中不建议使用。
推荐自定义多路复用器:
不同的URL对应不同处理器
package main
import (
"log"
"net/http"
"time"
)
func indexHandler(w http.ResponseWriter,r *http.Request){
w.Write([]byte(Go Web编程.基础入门