=Start=
缘由:
学习整理一下如何用Go 语言实现简单的HTTP服务,以便后续参考和使用。
正文:
参考解答:
1、一个超简单的HTTP服务样例
package main import ( "fmt" "log" "net/http" ) // w 表示response对象,返回给客户端的内容都在对象w里处理 // r 表示客户端请求对象,包含了请求头,请求参数等等 func index(w http.ResponseWriter, r *http.Request) { // 往w里写入内容,就会在浏览器里输出 fmt.Fprintf(w, "Hello golang http!") } func main() { // 设置路由,如果访问/,则调用index方法 http.HandleFunc("/", index) // 启动web服务,监听9090端口 err := http.ListenAndServe(":9090", nil) if err != nil { log.Fatal("ListenAndServe:9090", err) } }
保存为 go_http.go 然后用命令 go run go_http.go
启动HTTP服务。
2、提供静态文件Web服务
package main import ( "log" "net/http" ) func main() { // 一行代码实现,在 / 下提供文件服务 // log.Fatal(http.ListenAndServe(":9090", http.FileServer(http.Dir("/usr/share/doc")))) // 或 // 在指定 URL 下提供文件服务 // 将本地磁盘中的目录(/usr/share/doc)挂载在URL(/doc/)下面 // 可以使用 StripPrefix() 方法在 FileServer 看到请求之前修改请求URL的路径 http.Handle("/doc/", http.StripPrefix("/doc/", http.FileServer(http.Dir("/usr/share/doc")))) // 启动web服务,监听9090端口 err := http.ListenAndServe(":9090", nil) if err != nil { log.Fatal("ListenAndServe: ", err) } }
3、读取HTTP的header/form/body内容的样例
package main import ( "fmt" "io/ioutil" "log" "net/http" ) // w 表示response对象,返回给客户端的内容都在对象w里处理 // r 表示客户端请求对象,包含了请求头,请求参数等等 func index(w http.ResponseWriter, r *http.Request) { fmt.Printf("Request.Method: %v\n", r.Method) fmt.Println("Request.Header:") for name, value := range r.Header { fmt.Printf("%v: %v(%v)", name, value, len(value)) if len(value) > 1 { for idx, value := range value { fmt.Printf("\tidx: %v, value: %v\n", idx, value) } } else { fmt.Println() } } fmt.Println() r.ParseForm() fmt.Println("Request.Form:") for name, value := range r.Form { fmt.Printf("%v: %v(%v)", name, value, len(value)) if len(value) > 1 { for idx, value := range value { fmt.Printf("\tidx: %v, value: %v\n", idx, value) } } else { fmt.Println() } } fmt.Println() s, _ := ioutil.ReadAll(r.Body) //把 body 内容读入字符串 s fmt.Printf("Request.Body: %v\n", string(s)) fmt.Println() // 往w里写入内容,就会在浏览器里输出 fmt.Fprintf(w, "Hello golang http!") } func main() { // 简单的静态Web服务器 // log.Fatal(http.ListenAndServe(":9090", http.FileServer(http.Dir("/usr/share/doc")))) // // 设置路由,如果访问/,则调用index方法 http.HandleFunc("/", index) // 将本地磁盘中的目录(/tmp)挂载在URL(/tmpfiles/)下面 // 可以使用 StripPrefix() 方法在 FileServer 看到之前修改请求URL的路径 http.Handle("/tmpfiles/", http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("/tmp")))) // 启动web服务,监听9090端口 err := http.ListenAndServe(":9090", nil) if err != nil { log.Fatal("ListenAndServe: ", err) } }
主要起演示作用,如果想知道更多http.Request和http.ResponseWriter有哪些字段,可以达到什么功能,可以去godoc里面看,非常方便和简单。
type Request struct { Method string URL *url.URL Proto string // "HTTP/1.0" ProtoMajor int // 1 ProtoMinor int // 0 // Header = map[string][]string{ // "Accept-Encoding": {"gzip, deflate"}, // "Accept-Language": {"en-us"}, // "Foo": {"Bar", "two"}, // } Header Header // Body is the request's body. // // For client requests a nil body means the request has no // body, such as a GET request. The HTTP Client's Transport // is responsible for calling the Close method. // // For server requests the Request Body is always non-nil // but will return EOF immediately when no body is present. // The Server will close the request body. The ServeHTTP // Handler does not need to. Body io.ReadCloser // For server requests it is unused. GetBody func() (io.ReadCloser, error) ContentLength int64 TransferEncoding []string Close bool Host string // Form contains the parsed form data, including both the URL // field's query parameters and the POST or PUT form data. // This field is only available after ParseForm is called. // The HTTP client ignores Form and uses Body instead. Form url.Values // PostForm contains the parsed form data from POST, PATCH, // or PUT body parameters. // This field is only available after ParseForm is called. // The HTTP client ignores PostForm and uses Body instead. PostForm url.Values // MultipartForm is the parsed multipart form, including file uploads. // This field is only available after ParseMultipartForm is called. // The HTTP client ignores MultipartForm and uses Body instead. MultipartForm *multipart.Form // Few HTTP clients, servers, or proxies support HTTP trailers. Trailer Header // This field is ignored by the HTTP client. RemoteAddr string RequestURI string TLS *tls.ConnectionState Cancel <-chan struct{} Response *Response // contains filtered or unexported fields }
&
// url.Values type Values map[string][]string // url.URL type URL struct { Scheme string Opaque string // encoded opaque data User *Userinfo // username and password information Host string // host or host:port Path string RawPath string // encoded path hint (Go 1.5 and later only; see EscapedPath method) ForceQuery bool // append a query ('?') even if RawQuery is empty RawQuery string // encoded query values, without '?' Fragment string // fragment for references, without '#' }
参考链接:
- golang启动一个简单的http服务
- supervisor运行golang守护进程
- Pretty Printing HTTP Requests in Golang
- https://golang.org/pkg/net/http/
=END=
《 “Go语言学习#12-如何搭建HTTP服务” 》 有 3 条评论
【Go】优雅的读取http请求或响应的数据
https://blog.thinkeridea.com/201901/go/you_ya_de_du_qu_http_qing_qiu_huo_xiang_ying_de_shu_ju.html
`
背景介绍
我们有许多 api 服务,全部采用 json 数据格式,请求体就是整个 json 字符串,当一个请求到服务端会经过一些业务处理,然后再请求后面更多的服务,所有的服务之间都用 http 协议来通信(啊, 为啥不用 RPC,因为所有的服务都会对第三方开放,http + json 更好对接),大多数请求数据大小在 1K~4K,响应的数据在 1K~8K,早期所有的服务都使用 ioutil.ReadAll 来读取数据,随着流量增加使用 pprof 来分析发现 bytes.makeSlice 总是排在第一,并且占用了整个程序 1/10 的内存分配,我决定针对这个问题进行优化,下面是整个优化过程的记录。
使用合适大小的 buffer 来减少内存分配,sync.Pool 可以帮助复用 buffer, 一定要自己写这些逻辑,避免使用三方包,三方包即使使用同样的技巧为了避免数据争用,在返回数据时候必然会拷贝一个新的数据返回,就像 jsoniter 虽然使用了 sync.Pool 和 buffer 但是返回数据时还需要拷贝,另外这种通用包并不能给一个非常贴合业务的初始 buffer 大小,过小会导致数据发生拷贝,过大会太过浪费内存。
程序中善用 buffer 和 sync.Pool 可以大大的改善程序的性能,并且这两个组合在一起使用非常的简单,并不会使代码变的复杂。
`
zinx:基于 Golang 的轻量级 TCP 并发服务器框架
https://paper.tuisec.win/detail/224288f119a7a23
https://toutiao.io/posts/zn5zda/preview
https://www.jianshu.com/p/23d07c0a28e5
基于Golang解决的长连接并发服务器框架
https://github.com/aceld/zinx
`
Zinx源代码
完整教程电子版(在线高清)-下载
Zinx框架视频教程(框架篇)(完整版下载)链接在下面正文
Zinx框架视频教程(应用篇)(完整版下载)链接在下面正文
Zinx开发API文档
Zinx第一章-引言
Zinx第二章-初识Zinx框架
Zinx第三章-基础路由模块
Zinx第四章-全局配置
Zinx第五章-消息封装
Zinx第六章-多路由模式
Zinx第七章-读写分离模型
Zinx第八章-消息队列及多任务
Zinx第九章-链接管理
Zinx第十章-连接属性设置
`
HTTP/2 in GO(一)
https://mp.weixin.qq.com/s/5tcqd40by8GBSsnTQEo-OQ
HTTP/2 in GO(二)
https://mp.weixin.qq.com/s/eBhWbwv7UDhMFSeZFEOiHQ
HTTP/2 in GO(三)
https://mp.weixin.qq.com/s/3IgNBUJpHXKxp6wT6A8EjA
HTTP/2 in GO(四)
https://mp.weixin.qq.com/s/kKQuv9tK791eFxmqGRWy2Q
HTTP/2 in GO(五)–大结局
https://mp.weixin.qq.com/s/qaqN4Eqndjg95TPBOC4d_g