1. 怎么启动Web服务?

Go语言标准库内置的net/http包,可以实现HTTP服务端。实现HTTP服务端就是能够启动Web服务,相当于搭建起了一个Web服务器。 http.ListenAndServer()函数用来启动Web服务,绑定并监听http端口。

func ListenAndServe(addr string, handler Handler)// addr:监听地址;如 :8080 或者0.0.0.0:8080// handler:HTTP处理器Handler

2.启动Web服务的几种方式

根据不同服务返回的handler,常见启动Web服务有以下几种方式。

2.1 http.FileServer: 静态文件服务

http.FileServer()搭建的服务器只提供静态文件的访问。因为这种web服务只支持静态文件访问,所以称之为静态文件服务。

1.使用示例

文件目录如下:

package mainimport ( "net/http")func main() { runFileServer()}// 启动一个文件服务器func runFileServer()  { // 如果改路径下有index.html,则会优先显示index.html,否则会看到文件目录 http.ListenAndServe(":3000",http.FileServer(http.Dir("./public/")))}

注意: 启动的时候,需求使用go run main.go。否则会报404

2.2 http.HandleFunc: 默认的多路由分发服务

http.HandleFunc()的作用是注册网络访问的路由。因为它采用的是默认的路由分发任务方式,所以称之为默认的多路由分发服务。

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { DefaultServeMux.HandleFunc(pattern, handler)}// pattern:请求路径的匹配模式// handler:函数类型,表示这个请求需要处理的事情,其实就是Handler接口中的ServeHTTP()方法。

ServeHTTP()方法有两个参数,其中第一个参数是ResponseWriter类型,包含了服务器端给客户端的响应数据。服务器端往ResponseWriter写入了什么内容,浏览器的网页源码就是什么内容。第二个参数是一个 *Request指针,包含了客户端发送给服务器端的请求信息(路径、浏览器类型等)

1.使用示例
package mainimport ( "fmt" "net/http")func main() { // 绑定路由/hello http.HandleFunc("/hello",helloHandle) // 绑定路由到/test http.HandleFunc("/test",testHandle) // 启动服务 err := http.ListenAndServe(":5000",nil) fmt.Println(err)}// 处理路由hellofunc helloHandle(w http.ResponseWriter, r *http.Request)  { fmt.Println("访问路由hello") // 解析url参数 fmt.Println(r.URL.Query()) w.Write([]byte("hello word!"))}// 处理路由testfunc testHandle(w http.ResponseWriter, r *http.Request)  { fmt.Println("访问路由test") // 解析url参数,并输出 fmt.Println(r.URL.Query()) w.Write([]byte("test doing!"))}// 访问: http://127.0.0.1:5000/test?a=1001// 访问: http://127.0.0.1:5000/hello?b=990

通过http. HandleFunc()注册网络路由时,http.ListenAndServer()的第二个参数通常为nil,这意味着服务端采用默认的http.DefaultServeMux进行分发处理。

2.3 http.NewServeMux(): 自定义多路由分发服务

http.NewServeMux()的作用是注册网络访问的多路路由。因为它采用的是自定义的多路由分发任务方式,所以称之为自定义多路由分发服务。

注册网络路由时,如果http.ListenAndServer()的第二个参数为nil,那么表示服务端采用默认的http.DefaultServeMux进行分发处理。也可以自定义ServeMuxServeMux结构体如下

// ServeMux结构体源码type ServeMux struct { mu    sync.RWMutex // 锁,由于请求涉及到并发处理,因此这里有个锁机制  m     map[string]muxEntry // 存放具体的路由信息  es    []muxEntry // 按照路由长度从大到小的存放处理函数 hosts bool       // 标记路由中是否带有主机名}// muxEntry是路由的具体条目type muxEntry struct { h       Handler // 处理函数 pattern string  // 路由路径}

3. 自定义多路由实践

package mainimport ( "fmt" "net/http")// 定义一个接口体,用来实现http.Handlertype MyRoute struct {}// 实现http.Handler接口中的ServeHTTP方法func (m *MyRoute)ServeHTTP(w http.ResponseWriter,r *http.Request)  { path := r.URL.Path fmt.Println(path) switch path { case  "/":  w.Write([]byte("首页")) case "/hello":  w.Write([]byte("say hello")) case "/test":  w.Write([]byte("test doing")) default:  http.NotFound(w,r) } return}func main() { myRoute := &MyRoute{} http.ListenAndServe(":10000",myRoute)}

3.1 代码执行流程

使用http.ListenAndServe(":10000",myRoute)启动服务之后,会发生以下操作

1.实例化http.Server,并调用ListenAndServe()
func ListenAndServe(addr string, handler Handler) error {  // 实例化 Server server := &Server{Addr: addr, Handler: handler}  // 调用 ListenAndServe() return server.ListenAndServe()}
2.监听端口
   func (srv *Server) ListenAndServe() error {    if srv.shuttingDown() {     return ErrServerClosed    }    addr := srv.Addr    if addr == "" {     addr = ":http"    }     // 监听端口    ln, err := net.Listen("tcp", addr)    if err != nil {     return err    }     // 启动服务    return srv.Serve(ln)   }
3.启动for无限循环,在循环体中Accept请求,并开启 goroutine为这个请求服务
func (srv *Server) Serve(l net.Listener) error {   //...省略N行代码 for {  rw, err := l.Accept()  if err != nil {    //...省略N行代码  }  connCtx := ctx  if cc := srv.ConnContext; cc != nil {   connCtx = cc(connCtx, rw)   if connCtx == nil {    panic("ConnContext returned nil")   }  }  tempDelay = 0  c := srv.newConn(rw)  c.setState(c.rwc, StateNew)    // 开启goroutine为这个请求服务  go c.serve(connCtx) }}
4.读取每个请求内容,并调用ServeHTTP
func (c *conn) serve(ctx context.Context) { //...省略N行代码 for {    // 读取每个请求内容  w, err := c.readRequest(ctx)    //...省略N行代码

    // 调用ServeHTTP  serverHandler{c.server}.ServeHTTP(w, w.req)  //...省略N行代码} 
5. 判断handler是否为空,如果为空则把handler设置成DefaultServeMux
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { handler := sh.srv.Handler if handler == nil {    // 如果为空则把handler设置成DefaultServeMux。  handler = DefaultServeMux } if req.RequestURI == "*" && req.Method == "OPTIONS" {  handler = globalOptionsHandler{} }  // 上述示例中,传的是&MyRoute,所以会调用MyRoute.ServeHTTP handler.ServeHTTP(rw, req)}

微信搜索关注【猿码记】查看更多文章。

本文由 mdnice 多平台发布

Go学习(二十):启动HTTP服务的方式相关推荐

  1. linux samba 服务端口号,Linux系统学习 二十、SAMBA服务—介绍、安装、端口

    1.简介 网络数据文件共享服务器 可以和Windows中的网上邻居通用 数据共享的方法: Windows中最常用的是"网上邻居".网上邻居使用的文件系统是CIFS(通用互联网文件系 ...

  2. SAP UI5 初学者教程之二十六 - OData 服务配合 Mock 服务器的使用步骤详解试读版

    一套适合 SAP UI5 初学者循序渐进的学习教程 教程目录 SAP UI5 本地开发环境的搭建 SAP UI5 初学者教程之一:Hello World SAP UI5 初学者教程之二:SAP UI5 ...

  3. OpenCV学习(二十) :分水岭算法:watershed()

    OpenCV学习(二十) :分水岭算法:watershed() 参考博客: OpenCV-分水岭算法 图像处理--分水岭算法 OpenCV学习(7) 分水岭算法(1) Opencv分水岭算法--wat ...

  4. OpenCV学习(二十四 ):角点检测(Corner Detection):cornerHarris(),goodFeatureToTrack()

    OpenCV学习(二十四 ):角点检测(Corner Detection):cornerHarris(),goodFeatureToTrack() 参考博客: Harris角点检测原理详解 Harri ...

  5. OpenCV学习(二十二) :反向投影:calcBackProject(),mixChannels()

    OpenCV学习(二十二) :反向投影:calcHist(),minMaxLoc(),compareHist() 参考博客: 反向投影backproject的直观理解 opencv 反向投影 颜色直方 ...

  6. PyTorch框架学习二十——模型微调(Finetune)

    PyTorch框架学习二十--模型微调(Finetune) 一.Transfer Learning:迁移学习 二.Model Finetune:模型的迁移学习 三.看个例子:用ResNet18预训练模 ...

  7. C1认证学习二十六(基础选择器)

    C1认证学习二十六(基础选择器) 任务背景 CSS选择器是CSS规则的一部分,用来指定需要设置的样式的HTML元素,通过选择器可以实现CSS对HTML元素一对一或者一对多或者多对一的控制了啦. 任务目 ...

  8. 知识图谱论文阅读(八)【转】推荐系统遇上深度学习(二十六)--知识图谱与推荐系统结合之DKN模型原理及实现

    学习的博客: 推荐系统遇上深度学习(二十六)–知识图谱与推荐系统结合之DKN模型原理及实现 知识图谱特征学习的模型分类汇总 知识图谱嵌入(KGE):方法和应用的综述 论文: Knowledge Gra ...

  9. VUE学习(二十)、插槽

    VUE学习(二十).插槽 一.默认插槽 1.Category.vue <template><div class="category"><h3>{ ...

最新文章

  1. 报名 | 数据新闻发展趋势与人才培养学术讲座(武汉)
  2. (转载)一种根据纠偏数据对火星坐标进行完美拟合的方法
  3. Struts2中的配置文件--struts.properties文件
  4. lodoop打印控件详解
  5. [转载]jquery cookie的用法
  6. STM32的map文件学习笔记
  7. 三维叉乘怎么算_3分钟做完这些题,你的CAD才算熟练
  8. (12)Verilog HDL变量:reg型
  9. php fpm listen.owner,nginx 与 php-fpm socket 所有者权限问题
  10. antd 设置表头属性_React表格固定表头/锁定列
  11. oracle批量造测试数据
  12. Mysql安装(转自韩顺平教育)
  13. Win7 获取管理员权限
  14. 用java求水仙花数,适合新手
  15. 1014 福尔摩斯的约会 (20 分)
  16. 阴阳师召唤式神app(安卓)
  17. 26. SAP ABAP OData Gateway 框架里 /IWFND, /IWBEP 这些缩写代表了什么含义?
  18. 【PyTorch深度学习实践】08_Softmax分类器(多分类)
  19. 关于如何在WPS中生成附图索引
  20. 少儿编程值得报班学习吗?别问了,程序员懵了

热门文章

  1. 《怪物弹珠》新手技巧大彙整!!!下篇
  2. jquery 竖向实现组织结构图,自定义样式
  3. 邮寄信封地址打印办法
  4. 让人一夜暴富的区块链,新时代革命的开始
  5. 解决修改PyCharm源后添加源信任的问题
  6. 看服务器raid卡状态,查看服务器raid卡信息的shell脚本
  7. 通过图片和base64互转,实现图片上传和下载显示以及踩坑
  8. 几十款游戏的简单分析
  9. dede php语句调用,dede织梦在{dede:php}中调用文章id或aid
  10. MFC实现父窗口不透明,子窗口半透明效果