20 网络编程 Web 服务器

[TOC]

Web 服务器

  • Go 提供了一个完善的 net/http 包,通过 http 包很容易就可以搭建 Web 服务器。使用net/http包能很简单地对 Web 的路由、静态文件、模版、cookie 等数据进行设置和操作,不需要再去引入其它任何额外的依赖。

  • net/http 包也提供了HTTP客户端的相关API,可以很简单发起HTTP请求。

Go HTTP 服务器

net/http下 常用API

  • 注册处理函数 http.HandleFunc(资源url string, 资源对应处理函数))

  • 监听一个端口启动HTTP服务器 http.ListenAndServe("ip:port",nil)

HTTP 处理器和处理器函数

处理器需要实现Handler接口,接口有一个ServeHTTP(ResponseWriter, *Request)方法,任何实现了这个接口的类型都是处理器。

  • ListenAndServe 使用指定的监听地址和处理器启动一个HTTP服务端。处理器参数通常是nil,这表示采用包变量 DefaultServeMux 作为处理器。

  • Handle 和 HandleFunc 函数可以向 DefaultServeMux 添加处理器。

package main

import (
	"fmt"
	"net/http"
)

type MyHandler1 struct {}
func (h1 *MyHandler1) ServeHTTP(writer http.ResponseWriter,request *http.Request){
	fmt.Println("h1处理器")
	writer.Write([]byte("h1响应数据"))
}

type MyHandler2 struct {}
func (h2 *MyHandler2) ServeHTTP(write http.ResponseWriter,request *http.Request){
	fmt.Println("h2处理器")
	write.Write([]byte("h2响应数据"))
}

func main() {
	server := http.Server{
		Addr: "0.0.0.0:8080",
	}
	http.Handle("/h1",&MyHandler1{})
	http.Handle("/h2",&MyHandler2{})
	server.ListenAndServe()
//	分别访问 http://localhost:8080/h1 和 http://localhost:8080/h2,不同处理器监听了不同的 url
}

处理器函数是与处理器拥有相同行为的函数,它与ServeHTTP(ResponseWriter, *Request)方法有相同的签名。

读取数据 流方式

读取请求体body数据

  • 请求方式除了Get以外,其它请求方式数据都可在body中读取。

  • 如果body中的数据已经被读取,则其它方式都将读取不到数据。

读取表单数据 FormValue,读取Header数据

通过FormValue读取数据,可以读取Get请求和表单提交,但要注意,在非Get请求情况如果先把body数据读取了,再到FormValue是读取不到数据的。

  • 表单数据,增加请求头 【Content-Type:application/x-www-form-urlencoded】

  • 要读取表单数据要先 request.ParseForm()

  • 读取请求头使用 request.Header.Get(key)

  • 设置响应头 writer.Header().Set("test-header","test")

带有配置的Web服务器

要带配置的Web服务器使用http.Server,需要自定义Handler,自定义Handler需要实现Handler接口。

响应 json数据 application/json

响应状态码设置 重定向302

多路复用器 ServeMux 和 DefaultServeMux

ServeMux是一个HTTP请求多路复用器,它负责接收HTTP请求并根据请求中的URL将请求交给正确的处理器。

  • ServeMux结构包含了一个map,map会将URL作为key处理器作为value。

  • ServeMux结构也实现了ServeHTTP方法,所以它也是一个处理器,当ServeMux的ServeHTTP方法接收到一个请求的时候,它会在结构的map中找出被请求URL最为匹配的URL(绝对路径将会优先于相对路径),然后调用与之相应的处理器。

  • ServeMux不是接口而是一个结构体,所以DefaultServeMux并不是ServeMux的实现。

  • DefaultServeMux是ServeMux的一个实例,并且所有引入net/http标准库的程序都可以使用这个实例。如果没有指定ServeMux,服务器就会默认使用DefaultServeMux。

  • 第三方多路复用器 "github.com/julienschmidt/httprouter",有开发了一些新的功能(如从URL中提取出参数)。

多路复用器转发给处理器图

多路复用器转发给处理器图

多路复用器的工作原理

多路复用器的工作原理图

  • 多路复用器使用:

HTTP 静态资源处理器配置

静态资源处理器配置

  • http.FileServer 创建一个文件HTTP请求的处理器,文件路径在Dir下,【http.FileServer(http.Dir("./web/webapp/page"))】。配置的路径是从goPath开始的,在集成开发工具中是从项目根路径开始。

  • http.StripPrefix 如果URL前缀是prefix则URL会被TrimPrefix截去前缀,因为目录配置是【"./web/webapp/page"】访问的URL一般是http://域名/page/index.html,如果不截去前缀则会在【"./web/webapp/page/page/index.html"】,而实际上文件的目录在【"./web/webapp/page/index.html"】就会无法访问到而出现404。

  • http.Handle注册处理器,处理请求资源URL与"/page/"最匹配的。

使用 HTTPS

申请了SSL证书之后使用 ListenAndServeTLS 开启HTTPS。

  • 开启HTTPS模式启动服务器,服务器默认使用HTTP2。

Go HTTP 客户端

请求提交数据的常见编码格式有三种:

  • application/x-www-form-urlencoded 浏览器的原生form表单,如果不设置enctype属性,那么最终就会默认以application/x-www-form-urlencoded方式提交数据。这种情况下请求头的Content-Type被设置成application/x-www-form-urlencoded,提交的数据按照key1=value1&key2=value2的方式进行编码,key和value都进行了URL转码。大部分服务端语言都对这种方式有很好的支持。默认用Ajax提交数据时,也是使用这种方式。

  • multipart/form-data 是一个常见的POST数据提交的方式,表示在发送前不对数据进行编码,这种方式一般出现在通过form表单上传文件的场景中,在HTML的form标签中通过设置属性enctype=multipart/form-data来表示通过这种方式提交数据。上面提到的这两种POST数据的方式,都是浏览器原生支持的。各大服务端语言对它也有着良好的支持。

  • application/json 这个Content-Type请求头和响应头都很常见,用来告诉服务端消息主体是序列化后的JSON字符串。由于JSON规范的流行,除了低版本IE之外的各大浏览器都原生支持JSON.stringify,服务端语言也都有处理JSON的函数,使用JSON不会遇上什么麻烦。

Go 作为客户端发起HTTP请求

Get、Post 函数发出 HTTP/ HTTPS请求

http.NewRequest 管理HTTP客户端的头和其他设置

Transport

Client 和 Transport 类型都可以安全的被多个协程同时使用。出于效率考虑,应该一次建立、尽量重用。

  • transport的主要功能其实就是缓存了长连接,用于大量http请求场景下的连接复用,减少发送请求时TCP(TLS)连接建立的时间损耗,同时transport还能对连接做一些限制,如连接超时时间,每个host的最大连接数等。transport对长连接的缓存和控制仅限于TCP+(TLS)+HTTP1,不对HTTP2做缓存和限制。

Go 文件上传

接收文件上传服务器

HTML 表单上传文件

upload.html

  • 访问 http://localhost:19580/page/upload.html

Go 上传文件

Last updated