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. Thread.join详解

    /** * 如果某个线程在另一个线程t上调用t.join:那么此线程将被挂起,直到目标t线程的结束才恢复即t.isAlive返回为假 * * @date:2018年6月27日 * @author:zh ...

  2. tail常用命令总结

    tail命令作用: tail命令用途是依照要求将指定的文件的最后部分输出到标准设备,通常是终端,通俗讲来,就是把某个档案文件的最后几行显示到终端上,假设该档案有更新,tail会自己主动刷新,确保你看到 ...

  3. ZooKeeper集群“脑裂”

    ZooKeeper 集群节点为什么要部署成奇数ZooKeeper 容错指的是:当宕掉几个ZooKeeper节点服务器之后,剩下的个数必须大于宕掉的个数,也就是剩下的节点服务数必须大于n/2,这样Zoo ...

  4. .NET Core 中的日志与分布式链路追踪

    目录 .NET Core 中的日志与分布式链路追踪 .NET Core 中的日志 控制台输出 非侵入式日志 Microsoft.Extensions.Logging ILoggerFactory IL ...

  5. Netty的简单Demo

    这个demo是通过网上下载: 使用maven构建的: 项目结构: pom.xml: <dependencies> <dependency> <groupId>io. ...

  6. uni-app开发经验分享十四:小程序超过2M限制的方法——分包加载

      起初小程序上线时,微信限制了代码包不能超过1MB,后来功能变大变成了2M了,限制大小是出于对小程序启动速度的考虑,希望用户在使用任何一款小程序时,都能获得一种"秒开"体验.但是 ...

  7. ROS教程(一):ROS安装教程(详细图文)

    ros教程:ros安装 目录 前言 一.版本选择 二.开始安装 2.1 软件中心配置 2.2 添加源 2.3 安装 三.验证ROS 前言 关于ROS(Robot OS 机器人操作系统),估计看这个教程 ...

  8. JVM(五)手动解析.class文件

    一:不同进制之间的转换 二进制:逢2进1,数字0-1. 八进制:逢8进1,数字0-7.三位二进制表示一位八进制.三位二进制最大为111,最大为7. 十进制:逢10进1,数字0-9.四位二进制表示一位十 ...

  9. python3多进程 进程池 协程并发

    一.进程           我们电脑的应用程序,都是进程,进程是资源分配的单位.进程切换需要的资源最大,效率低.         进程之间相互独立         cpu密集的时候适合用多进程 #多 ...

  10. ADB 基本命令

    ADB很强大,记住一些ADB命令有助于提高工作效率. 获取序列号: adb get-serialno 查看连接计算机的设备: adb devices 重启机器: adb reboot 重启到bootl ...