一.web开发简介
1.简介
Web应用在我们的生活中无处不在,看看我们日常使用的各个应用程序,它们要么是 Web应用,要么是移动 App 这类 web应用的变种,无论哪一种编程语言,只要它能够开发出与人类交互的软件,它就必然会支持 Web应用开发,对一门崭新的编程语言来说,它的开发者首先要做的一件事,就是构建与互联网( Internet )和万维网( World Wide Web )交互的库(Iibrary )和框架,而那些更为成熟的编程语言还会有各种五花八门的Web开发工具
Go是一门刚开始崭露头角的语言,它是为了让人们能够简单而高效地编写后端系统而创建的,这门语言拥有众多的先进特性,如函数式编程方面的特性、内置了对并发编程的支持、现代化的包管理系统、垃圾收集特性、以及一些包罗万象威力强大的标准库,而且如果需要还可以引入第三方开源库
使用go语言进行web开发变得日益流行,很多公司都在用,如谷歌,Facebook,腾讯,百度,阿里巴巴,京东,小米,360,美团等
2.web应用的工作原理
3.代码入门
main.go
package main
import (
"fmt"
"net/http"
)
//创建一个处理器函数
func handler(w http.ResponseWriter, r *http.Request) {
n, _ := fmt.Fprintln(w, "hello world", r.URL.Path)
fmt.Println(n)
}
func main() {
//初始化路有路由
http.HandleFunc("/", handler)
//创建路由
//ListenAndServe监听TCP地址addr,并且会使用handler参数调用Serve函数处理接收到的连接。
//handler参数一般会设为nil,此时会使用DefaultServeMux
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Println(err)
}
}
使用go build main.go生成main.exe后,双击, 浏览器访问:localhost:8080/hello,结果:
二.web服务器的搭建
1.简介
GO 提供了一系列用于创建 Web服务器的标准库,而且通过 GO 创建一个服务器的步骤非常简单,只要通过net/http包调用ListenAndServe函数并传入网络地址以及负责处理请求的处理器(handler)作为参数就可以了,如果网络地址参数为空字符串,那么服务器默认使用 80 端口进行网络连接;如果处理器参数为 niI ,那么服务器将使用默认的多路复用器 DefaultServeMux,当然,也可以通过调用 NewServeMux 函数创建一个多路复用器,多路复用器接收到用户的请求之后根据请求的 URL 来判断使用哪个处理器来处理请求,找到后就会重定向到对应的处理器来处理请求
2.使用默认的多路复用器(DefaultServerMux)
package main
import (
"fmt"
"net/http"
)
//创建一个处理器函数
func handler(w http.ResponseWriter, r *http.Request) {
n, _ := fmt.Fprintln(w, "hello world", r.URL.Path)
fmt.Println(n)
}
func main() {
//映射地址: 请求过来后,调用哪一个处理器
http.HandleFunc("/", handler)
//创建路由
//ListenAndServe监听TCP地址addr,并且会使用handler参数调用Serve函数处理接收到的连接。
//handler参数一般会设为nil 默认调用系统设定的多路复用器,此时会使用DefaultServeMux
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Println(err)
}
}
处理器函数的实现原理
go语言拥有一种HandlerFunc函数类型,可以将一个带有正确签名的函数f转换成一个带有方法f的Handler
Handle方法的说明
关于处理器Handler的说明
也就是说只要某个结构体实现了Handler接口中的SerHTTP方法,那么它就是一个处理器
代码如下:
package main
import (
"fmt"
"net/http"
)
type MyHandler struct {
}
//创建结构体MyHandler对应的Handler接口的ServeHTTP方法
func (m *MyHandler)ServeHTTP(w http.ResponseWriter, r *http.Request) {
n, _ := fmt.Fprintln(w, "my handler", r.URL.Path)
fmt.Println(n)
}
func main() {
//创建一个MyHandler实例
myHandler := MyHandler{}
//映射地址: 请求过来后,调用哪一个处理器
http.Handle("/myHandler", &myHandler)
//创建路由
//ListenAndServe监听TCP地址addr,并且会使用handler参数调用Serve函数处理接收到的连接。
//handler参数一般会设为nil 默认调用系统设定的多路复用器,此时会使用DefaultServeMux
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Println(err)
}
}
还可以通过Server结构对服务器进行更详细的配置
package main
import (
"fmt"
"net/http"
"time"
)
type MyHandler struct {
}
//创建结构体MyHandler对应的Handler接口的ServeHTTP方法
func (m *MyHandler)ServeHTTP(w http.ResponseWriter, r *http.Request) {
n, _ := fmt.Fprintln(w, "my handler server func", r.URL.Path)
fmt.Println(n)
}
func main() {
//创建一个MyHandler实例
myHandler := MyHandler{}
//创建server结构,并详细配置里面的字段
server := http.Server{
Addr: ":8080",
Handler: &myHandler,
ReadTimeout: 2 * time.Second,
}
//调用server中的ListenAndServe方法
err := server.ListenAndServe()
if err != nil {
fmt.Println(err)
}
}
3.使用自己创建的多路复用器
在创建服务器时,可以通过NewServeMux方法创建一个多路复用器
package main
import (
"fmt"
"net/http"
)
//创建一个处理器函数
func handler(w http.ResponseWriter, r *http.Request) {
n, _ := fmt.Fprintln(w, "hello world", r.URL.Path)
fmt.Println(n)
}
func main() {
//自定义多路复用器
mux := http.NewServeMux()
//映射地址: 请求过来后,调用哪一个处理器
mux.HandleFunc("/myMux", handler)
//创建路由
//ListenAndServe监听TCP地址addr,并且会使用handler参数调用Serve函数处理接收到的连接。
//handler参数一般会设为nil 默认调用系统设定的多路复用器,此时会使用DefaultServeMux
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Println(err)
}
}
package main
import (
"fmt"
"net/http"
)
//创建一个处理器函数
func handler(w http.ResponseWriter, r *http.Request) {
n, _ := fmt.Fprintln(w, "hello world", r.URL.Path)
fmt.Println(n)
}
func main() {
//自定义多路复用器
mux := http.NewServeMux()
//映射地址: 请求过来后,调用哪一个处理器
mux.HandleFunc("/", handler)
//创建路由
//ListenAndServe监听TCP地址addr,并且会使用handler参数调用Serve函数处理接收到的连接。
//handler参数一般会设为nil 默认调用系统设定的多路复用器,此时会使用DefaultServeMux
err := http.ListenAndServe(":8080", mux)
if err != nil {
fmt.Println(err)
}
}
三.http协议
1.简介
HTTP 超文本传输协议( HTTP-Hypertext transfer protocol ) ,是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于 1990 年提出,经过几年的使用与发展,得到不断地完善和扩展。它是一种详细规定了浏览器和万维网服务器之间互相通信的规则,通过因特网传送万维网文档的数据传送协议。
客户端与服务端通信时传输的内容我们称之为报文,HTTP 就是一个通信规则,这个规则规定了客户端发送给服务器的报文格式,也规定了服务器发送给客户端的报文格式, 实际我们要学习的就是这两种报文。客户端发送给服务器的称为”请求报文",服务器发送给客户端的称为”响应报文"
2.http协议的发展历程
超文本传输协议的前身是世外桃源( xanadu )项目,超文本的概念是泰德’纳尔森(Ted Nelson )在1960年代提出的,进入哈佛大学后,纳尔森一直致力于超文本协议和该项目的研究,但他从未公开发表过资料, 1989 年.蒂姆’伯纳斯’李( Tim Berners Lee )在 CERN (欧洲原子核研究委员会 = European Organization for Nuclear Research )担任软件咨询师的时候.开发了一套程序,确定了万维网(www=World Wide Web)的基础.1990 年 12 月,超文本在 CERN 首次上线。 1991 年夏天,继Telnet 等协议之后,超文本传输协议成为互联网诸多协议的一分子
3.http协议的会话方式
4.http1.0和http1.1的区别
在http1.0版本中,浏览器请求一个带有图片的网页,会由于下载图片而与服务器之间开启一个新的连接;但在http1.1版本中,允许浏览器在拿到当前请求对应的全部资源后再断开连接,提高了效率
5.报文
5.1报文格式
5.2请求报文
---- 请求行 ----GET / HTTP/1.1 # GET请求方式 请求资源路径 HTTP协议版本
---- 请求头 -----
Host: www.itcast.cn # 服务器的主机地址和端口号,默认是80
Connection: keep-alive # 和服务端保持长连接
Upgrade-Insecure-Requests: 1 # 让浏览器升级不安全请求,使用https请求
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 # 用户代理,也就是客户端的名称
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 # 可接受的数据类型
Accept-Encoding: gzip, deflate # 可接受的压缩格式
Accept-Language: zh-CN,zh;q=0.9 #可接受的语言
Cookie: pgv_pvi=1246921728; # 登录用户的身份标识
---- 空行 ----
注意:GET请求没有请求体,POST请求才有请求体
Header | 解释 | 示例 |
http请求头 | ||
Accept | 告诉WEB服务器自己接受什么介质类型,*/* 表示任何类型,type/* 表示该类型下的所有子类型,type/sub-type | Accept: text/plain, text/html |
Accept-Charset | 浏览器告诉服务器自己能接收的字符集。 | Accept-Charset: iso-8859-5 |
Accept-Encoding | 浏览器申明自己接收的编码方法,通常指定压缩方法,是否支持压缩,支持什么压缩方法(gzip,deflate)。 | Accept-Encoding: compress, gzip |
Accept-Language | 浏览器申明自己接收的语言。语言跟字符集的区别:中文是语言,中文有多种字符集,比如big5,gb2312,gbk等等 | Accept-Language: zh-CN |
Authorization | 当客户端接收到来自WEB服务器的 WWW-Authenticate 响应时,用该头部来回应自己的身份验证信息给WEB服务器。 | Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
If-Match | 如果对象的 ETag 没有改变,其实也就意味著对象没有改变,才执行请求的动作,获取文档 | If-Match: “737060cd8c284d8af7ad3082f209582d” |
If-None-Match | 如果对象的 ETag 改变了,其实也就意味著对象也改变了,才执行请求的动作,获取文档 | If-None-Match: “737060cd8c284d8af7ad3082f209582d” |
If-Modified-Since | 如果请求的对象在该头部指定的时间之后修改了,才执行请求的动作(比如返回对象),否则返回代码304,告诉浏览器该对象没有修改。 | If-Modified-Since:Thu, 10 May 2020 09:14:42 GMT |
If-Unmodified-Since | 如果请求的对象在该头部指定的时间之后没修改过,才执行请求的动作(比如返回对象) | If-Unmodified-Since: Sat, 29 May 2020 19:43:31 GMT |
If-Range | 浏览器告诉 WEB 服务器,如果我请求的对象没有改变,就把我缺少的部分给我,如果对象改变了,就把整个对象给我。浏览器通过发送请求对象的ETag 或者自己所知道的最后修改时间给 WEB 服务器,让其判断对象是否改变了。总是跟 Range 头部一起使用。 | If-Range: “737060cd8c284d8af7ad3082f209582d” |
Range | 浏览器(比如 Flashget 多线程下载时)告诉 WEB 服务器自己想取对象的哪部分 | Range: bytes=1173546 |
Proxy-Authorization | 代理服务器响应浏览器,要求其提供代理身份验证信息 | Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
Host | 客户端指定自己想访问的WEB服务器的域名/IP 地址和端口号 | Host:rss.sina.com.cn |
Referer | 浏览器向WEB 服务器表明自己是从哪个网页URL获得点击当前请求中的网址/URL | Referer:http://www.ecdoer.com/ |
User-Agent | 浏览器表明自己的身份(是哪种浏览器) | User-Agent:Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN;rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14 |
5.3响应报文
给一个例子:
HTTP/1.1 200 OK
Content-Type: text/html
Last-Modified: Wed, 01 Sep 2021 08:15:51 GMT
Accept-Ranges: bytes
ETag: "5173d69399fd71:0"
Server: Microsoft-IIS/10.0
Date: Wed, 29 Jun 2022 05:46:31 GMT
Content-Length: 52891
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" cnotallow="ie=edge">
<title>Artom - Modern & Multipurpose HTML Template</title>
<meta name="description" cnotallow="">
<meta name="viewport" cnotallow="width=device-width, initial-scale=1">
...
<script src="js/wow.min.js"></script>
<script src="js/aos.js"></script>
<script src="js/plugins.js"></script>
<script src="js/main.js"></script>
</body></html>
响应头:
Accept-Ranges | 表明服务器是否支持指定范围请求及哪种类型的分段请求 | Accept-Ranges: bytes |
Age | 从原始服务器到代理缓存形成的估算时间(以秒计,非负) | Age: 12 |
Allow | 对某网络资源的有效的请求行为,不允许则返回405 | Allow: GET, HEAD |
Cache-Control | 告诉所有的缓存机制是否可以缓存及哪种类型 | Cache-Control: no-cache |
Content-Encoding | web服务器支持的返回内容压缩编码类型。 | Content-Encoding: gzip |
Content-Language | 响应体的语言 | Content-Language: en,zh |
Content-Length | 响应体的长度 | Content-Length: 348 |
Content-Location | 请求资源可替代的备用的另一地址 | Content-Location: /index.htm |
Content-MD5 | 返回资源的MD5校验值 | Content-MD5: Q2hlY2sgSW50ZWdyaXR5IQ== |
Content-Range | 在整个返回体中本部分的字节位置 | Content-Range: bytes 21010-47021/47022 |
Content-Type | 返回内容的MIME类型 | Content-Type: text/html; charset=utf-8 |
Date | 原始服务器消息发出的时间 | Date: Tue, 15 Nov 2010 08:12:31 GMT |
ETag | 请求变量的实体标签的当前值 | ETag: “737060cd8c284d8af7ad3082f209582d” |
Expires | 响应过期的日期和时间 | Expires: Thu, 01 Dec 2010 16:00:00 GMT |
Last-Modified | 请求资源的最后修改时间 | Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT |
Location | 用来重定向接收方到非请求URL的位置来完成请求或标识新的资源 | Location: https://www.jisuan.mobi/ |
Pragma | 包括实现特定的指令,它可应用到响应链上的任何接收方 | Pragma: no-cache |
Proxy-Authenticate | 它指出认证方案和可应用到代理的该URL上的参数 | Proxy-Authenticate: Basic |
refresh | 应用于重定向或一个新的资源被创造,在5秒之后重定向(由网景提出,被大部分浏览器支持) | Refresh: 5; url= |
Retry-After | 如果实体暂时不可取,通知客户端在指定时间之后再次尝试 | Retry-After: 120 |
Server | web服务器软件名称 | Server: Apache/1.3.27 (Unix) (Red-Hat/Linux) |
Set-Cookie | 设置Http Cookie | Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1 |
Trailer | 指出头域在分块传输编码的尾部存在 | Trailer: Max-Forwards |
Transfer-Encoding | 文件传输编码 | Transfer-Encoding:chunked |
Vary | 告诉下游代理是使用缓存响应还是从原始服务器请求 | Vary: * |
Via | 告知代理客户端响应是通过哪里发送的 | Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1) |
Warning | 警告实体可能存在的问题 | Warning: 199 Miscellaneous warning |
WWW-Authenticate | 表明客户端请求实体应该使用的授权方案 | WWW-Authenticate: Basic |
6.响应状态码
常见状态码:
1xx:表示成功接收请求,要求客户端继续提交下一次请求才能完成整个处理过程
2xx:表示成功接收请求并已完成整个处理过程,常用200
3xx:为完成请求,客户需进一步细化请求。例如:请求的资源已经移动一个新地址、常用302(意味着你请求我,我让你去找别人),307和304(我不给你这个资源,自己拿缓存)
4xx:客户端的请求有错误,常用404(意味着你请求的资源在web服务器中没有),403(服务器拒绝访问,权限不够)
5xx:服务器端出现错误,常用500
状态码 | 含义 |
100 | 继续。客户端应继续其请求 |
101 | 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议 |
200 | 请求成功。一般用于GET与POST请求 |
201 | 已创建。成功请求并创建了新的资源 |
202 | 已接受。已经接受请求,但未处理完成 |
203 | 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本 |
204 | 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档 |
205 | 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域 |
206 | 部分内容。服务器成功处理了部分GET请求 |
300 | 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择 |
301 | 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替 |
302 | 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI |
303 | 查看其它地址。与301类似。使用GET和POST请求查看 |
304 | 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源 |
305 | 使用代理。所请求的资源必须通过代理访问 |
306 | 已经被废弃的HTTP状态码 |
307 | 临时重定向。与302类似。使用GET请求重定向 |
400 | 客户端请求的语法错误,服务器无法理解 |
401 | 请求要求用户的身份认证 |
402 | 保留,将来使用 |
403 | 服务器理解请求客户端的请求,但是拒绝执行此请求 |
404 | 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置"您所请求的资源无法找到"的个性页面 |
405 | 客户端请求中的方法被禁止 |
406 | 服务器无法根据客户端请求的内容特性完成请求 |
407 | 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权 |
408 | 服务器等待客户端发送的请求时间过长,超时 |
409 | 服务器完成客户端的 PUT 请求时可能返回此代码,服务器处理请求时发生了冲突 |
410 | 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置 |
411 | 服务器无法处理客户端发送的不带Content-Length的请求信息 |
412 | 客户端请求信息的先决条件错误 |
413 | 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息 |
414 | 请求的URI过长(URI通常为网址),服务器无法处理 |
415 | 服务器无法处理请求附带的媒体格式 |
416 | 客户端请求的范围无效 |
417 | 服务器无法满足Expect的请求头信息 |
500 | 服务器内部错误,无法完成请求 |
501 | 服务器不支持请求的功能,无法完成请求 |
502 | 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应 |
503 | 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中 |
504 | 充当网关或代理的服务器,未及时从远端服务器获取请求 |
505 | 服务器不支持请求的HTTP协议的版本,无法完成处理 |
[下一节] [golang Web开发] 2.golang web开发:操作数据库,增删改查,单元测试