=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