package main

import (
"net/http"
"fmt"
"strings"
"log"
) func sayHelloName(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
fmt.Println(r.Form)
fmt.Println("url", r.URL.Path)
fmt.Println("scheme", r.URL.Scheme)
fmt.Println(r.Form["url_long"])
for k, v:=range r.Form {
fmt.Println("key:", k)
fmt.Println("value:", strings.Join(v, ""))
}
fmt.Fprintln(w, "hello web")
} func main() {
http.HandleFunc("/", sayHelloName)
err := http.ListenAndServe(":9876", nil)
if err!= nil {
log.Fatal("ListenAndServe ", err)
}
}

先看一个最基本的golang的web服务器代码。main中在HandleFunc中设置了路由,然后调用ListenAndServe选择监听的接口和路由方法(这里路由方法制空,即调用了默认的路由,即HandleFunc设置的路由)。

LestenAndServe调用了http库中的serve方法,代码如下:

func (srv *Server) Serve(l net.Listener) error {
defer l.Close()
if fn := testHookServerServe; fn != nil {
fn(srv, l)
}
var tempDelay time.Duration // how long to sleep on accept failure if err := srv.setupHTTP2_Serve(); err != nil {
return err
} srv.trackListener(l, true)
defer srv.trackListener(l, false) baseCtx := context.Background() // base is always background, per Issue 16220
ctx := context.WithValue(baseCtx, ServerContextKey, srv)
for {
rw, e := l.Accept()
if e != nil {
select {
case <-srv.getDoneChan():
return ErrServerClosed
default:
}
if ne, ok := e.(net.Error); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
time.Sleep(tempDelay)
continue
}
return e
}
tempDelay = 0
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
go c.serve(ctx)
}
}

可以看到,serve建立了一个循环来监听请求。在接收到连接请求后,先接受请求,然后新建了连接,并利用go新建了线程来处理新的连接。这就是golang在处理web请求上支持高并发的根本。同时也保证了每个连接的独立性。

路由设置:

func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
handler := sh.srv.Handler
if handler == nil {
handler = DefaultServeMux
}
if req.RequestURI == "*" && req.Method == "OPTIONS" {
handler = globalOptionsHandler{}
}
handler.ServeHTTP(rw, req)
}

ServeHTTP方法负责设置路由。可以看到,如果handler为空,就使用默认路由。否则就使用自定义路由。这个方法是Handler接口中规定的唯一方法。对于我们的例子,sayHelloName方法并没有实现这个方法,仍然实现了Handler接口。这是因为HandleFunc方法将路由实现方法强制转换为HandleFunc类型。该方法实现了Handler接口。

handler处理方法如下:

func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {
mux.mu.RLock()
defer mux.mu.RUnlock() // Host-specific pattern takes precedence over generic ones
if mux.hosts {
h, pattern = mux.match(host + path)
}
if h == nil {
h, pattern = mux.match(path)
}
if h == nil {
h, pattern = NotFoundHandler(), ""
}
return
}

可以看到其匹配路由的方式。

根据以上的内容,我们也可以自己自定义路由。自定义路只需实现Handler接口。

type MyMux struct {
} func (m *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
sayHelloName(w, r)
return
}
http.NotFound(w, r)
return
} func main() {
mux := &MyMux{}
http.ListenAndServe(":9876", mux)
}

Golang内建库学习笔记(2)-web服务器相关的更多相关文章

  1. Golang内建库学习笔记(1)-sort和container

    sort库 利用sort.Sort进行排序须实现如下接口 type Interface interface { // 获取数据集合元素个数 Len() int // 如果i索引的数据小于j所以的数据, ...

  2. 06-Node.js学习笔记-创建web服务器

    创建web服务器 //引用系统模块 const http = require('http'); //创建web服务器 //用于处理url地址 const url = require('url'); c ...

  3. go语言,golang学习笔记2 web框架选择

    go语言,golang学习笔记2 web框架选择 用什么go web框架比较好呢?能不能推荐个中文资料多的web框架呢? beego框架用的人最多,中文资料最多 首页 - beego: 简约 & ...

  4. Spring实战第六章学习笔记————渲染Web视图

    Spring实战第六章学习笔记----渲染Web视图 理解视图解析 在之前所编写的控制器方法都没有直接产生浏览器所需的HTML.这些方法只是将一些数据传入到模型中然后再将模型传递给一个用来渲染的视图. ...

  5. golang日志框架--logrus学习笔记

    golang日志框架--logrus学习笔记 golang标准库的日志框架非常简单,仅仅提供了print,panic和fatal三个函数,对于更精细的日志级别.日志文件分割以及日志分发等方面并没有提供 ...

  6. muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制

    目录 muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制 eventfd的使用 eventfd系统函数 使用示例 EventLoop对eventfd的封装 工作时序 runInLoo ...

  7. muduo网络库学习笔记(三)TimerQueue定时器队列

    目录 muduo网络库学习笔记(三)TimerQueue定时器队列 Linux中的时间函数 timerfd简单使用介绍 timerfd示例 muduo中对timerfd的封装 TimerQueue的结 ...

  8. numpy, matplotlib库学习笔记

    Numpy库学习笔记: 1.array()   创建数组或者转化数组 例如,把列表转化为数组 >>>Np.array([1,2,3,4,5]) Array([1,2,3,4,5]) ...

  9. muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor

    目录 muduo网络库学习笔记(五) 链接器Connector与监听器Acceptor Connector 系统函数connect 处理非阻塞connect的步骤: Connetor时序图 Accep ...

随机推荐

  1. IT 界那些朗朗上口的“名言

    中国有很多古代警世名言,朗朗上口,凝聚了很多故事与哲理.硅谷的互联网公司里头也有一些这样的名言,凝聚了很多公司价值观和做事的方法,对于很多程序员来说,其影响潜移默化.这里收集了一些,如下. Stay ...

  2. 二进制格式mysql

    1.二进制MySQL安装 #下载二进制格式的mysql软件包 wget https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.31- ...

  3. Modbus java slave app

    文章实现 Modbus slave app , 用 serial rtu 传输, 代码只实现监听功能(本人测试可行), 要实现写功能,可研究一下代码中 updateProcessImage 方法.完整 ...

  4. CVE-2021-3019 漏洞细节纰漏

    CVE编号 CVE-2021-3019 lanproxy任意文件读取 该漏洞是2021年比较新的漏洞 是否需要认证:否 是否执行远程代码:否 是否执行远程命令:否 数据读取是否内网:否 漏洞软件介绍 ...

  5. 循序渐进VUE+Element 前端应用开发(32)--- 手机短信动态码登陆处理

    在一些系统中,有时候用户忘记密码,可以通过向自己手机发送动态验证码的方式实现系统登录功能.本篇随笔介绍如何结合后端ABP框架的短信发送和缓存模块的处理,实现手机短信动态码登陆处理. 一般的登录方式,分 ...

  6. mysql远程访问被拒绝问题

    远程连接MySql数据库时: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES) 远 ...

  7. 【Java基础】多线程

    多线程 基本概念 程序(program)是为完成特定任务.用某种语言编写的一组指令的集合.即指一段静态的代码,静态对象. 进程(process)是程序的一次执行过程,或是正在运行的一个程序.是一个动态 ...

  8. LeetCode344 反转字符串

    编写一个函数,其作用是将输入的字符串反转过来. 示例 1: 输入: "hello" 输出: "olleh" 示例 2: 输入: "A man, a p ...

  9. 【C++】《C++ Primer 》第十二章

    第十二章 动态内存 目前为止,所使用的对象都有着严格定义的生存期. 全局对象在程序启动时分配,在程序结束时销毁.局部自动对象在进入其定义所在的程序块时被创建,在离开块时销毁.局部static对象在第一 ...

  10. Java开发手册之编程规约

    时隔一年多,再次开始更新博客,各位粉丝们久等了.大家是不是以为我像大多数开发者一样三分钟热度,坚持了一年半载就放弃了,其实不是.在过去的一年时间我学习了<Java编程思想>这本书,因为都是 ...