GO web学习(一)
跟着b站https://space.bilibili.com/361469957 杨旭老师学习做的笔记
开启web服务
•http.ListenAndServer()
•第一个参数是网络地址 如果为“”,那么就是所有网络接口的 80 端口
•第二个参数是 handler 如果为 nil,那么就是 DefaultServeMux
•DefaultServeMux 是一个 multiplexer(可以看作是路由器)
•http.Server 这是一个 struct
Addr 字段表示网络地址 如果为“”,那么就是所有网络接口的 80 端口
•Handler 字段 如果为 nil,那么就是 DefaultServeMux
•ListenAndServe() 函数
因此开启服务器有两种方法
1. •http.ListenAndServer() //http
•http.ListenAndServeTLS() //https
2. •http.Server 可配置
•server.ListenAndServe() //http
•server.ListenAndServeTLS() //https
//s1和s2函数等效
func s1(){
server:= http.Server{
Addr: "localhost:8080",
Handler: nil,
}
server.ListenAndServe()
}
func s2(){
http.ListenAndServe("localhost:8080",nil)
}
Handle 请求
handler
•handler 是一个接口(interface)
•handler 定义了一个方法 ServeHTTP()
•http.ResponseWriter
•*http.Request 指向 Request 这个 struct 的指针
type Handler interface {
ServeHTTP(ResponseWriter,*Request)
}
DefaultServeMux
DefaultServeMux 是一个 multiplexer(可以看作是路由器)
•它也是一个 Handler
多个handler
•不指定 Server struct 里面的 Handler 字段值
•可以使用 http.Handle 将某个 Handler 附加到 DefaultServeMux
•http 包有一个 Handle 函数
•ServerMux struct 也有一个 Handle 方法
•如果你调用 http.Handle,实际上调用的是 DefaultServeMux 上的 Handle 方法
•DefaultServeMux 就是 ServerMux 的指针变量
type myHandler struct{}
type aboutHandler struct{}
func(m *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){
w.Write([]byte("一个美丽的日子"))
}
func (a *aboutHandler) ServeHTTP(w http.ResponseWriter,r *http.Request){
w.Write([]byte("about!"))
}
func myselfHandle(){
mh := myHandler{}
server:= http.Server{
Addr: "localhost:8080",
Handler: &mh,
}
server.ListenAndServe()
// 现在它就可以作为Handler用了
// 我们打开网址发现不管是localhost:8080/ 还是 localhost:8080/hello 等等
// 都会出现 一个美丽的日子
// 因为它直接走的是myHandler,而不是那个DefaultServeMux(下分handler,分地址注册)
// 所以多地址都对应myHandler,而DefaultServeMux,地址是分开对应的
}
func welcome(w http.ResponseWriter, r *http.Request){
w.Write([]byte("welcome"))
}
func index(w http.ResponseWriter, r *http.Request){
w.Write([]byte("index"))
}
func myselfHandlePro(){
mh := myHandler{}
ah := aboutHandler{}
server:= http.Server{
Addr: "localhost:8080",
Handler: nil, //DefaultServeMux
}
http.Handle("/hello",&mh)
http.Handle("/about",&ah)
http.HandleFunc("/home",func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Home"))
})
http.Handle("/welcome",http.HandlerFunc(welcome))
http.HandleFunc("/index",index)
server.ListenAndServe()
}
handle请求的两种形式
1.http.Handle
•第二个参数是 Handler
2.http.HandleFunc
•第二个参数是一个 Handler 函数
•http.HandlerFunc 可以把 Handler 函数转化为 Handler
•内部调用的还是 http.Handle 函数
内置的handlers
404 not found
1.http.NotFoundHandler
func NotFoundHandler() Handler
返回一个 handler,它给每个请求的响应都是“404 page not found”
重定向
2.http.RedirectHandler
func RedirectHandler(url string, code int) Handler
返回一个 handler,它把每个请求使用给定的状态码跳转到指定的 URL。
url,要跳转到的 URL
code,跳转的状态码(3xx),常见的:StatusMovedPermanently、StatusFound 或 StatusSeeOther 等
路径处理
3.http.StripPrefix
func StripPrefix(prefix string, h handler) Handler
返回一个 handler,它从请求 URL 中去掉指定的前缀,然后再调用另一个 handler。
如果请求的 URL 与提供的前缀不符,那么 404
略像中间件
prefix,URL 将要被移除的字符串前缀
h,是一个 handler,在移除字符串前缀之后,这个 handler 将会接收到请求
修饰了另一个 Handler
超时处理
4.http.TimeoutHandler
func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler
返回一个 handler,它用来在指定时间内运行传入的 h。
也相当于是一个修饰器
h,将要被修饰的 handler
dt,第一个 handler 允许的处理时间
msg,如果超时,那么就把 msg 返回给请求,表示响应时间过长
文件服务
5.http.FileServer
func FileServer(root FileSystem) Handler
返回一个 handler,使用基于 root 的文件系统来响应请求
type FileSystem interface {
Open(name string) (File, error)
}
使用时需要用到操作系统的文件系统,所以还需要委托给:
type Dir string
func (d Dir) Open(name string) (File, error)
http.ListenAndServe(":8080",http.FileServer(http.Dir("wwwroot")))
http.HandleFunc("/",func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w,r,"wwwroot"+r.URL.Path)
})
http.ListenAndServe(":8080",nil)
这两个都是打开wwwroot目录下的文件,而且路径不需要加wwwroot/
Request 请求
http消息
•HTTP Request 和 HTTPResponse(请求和响应)
•它们具有相同的结构:
•请求(响应)行
•0 个或多个 Header
•空行
•可选的消息体(Body)
•例子:
GET
/Protocols/rfc2616/rfc2616.html HTTP/1.1
Host:www.w3.org
User-Agent:Mozilla/5.0
(空行)
•net/http 包提供了用于表示 HTTP 消息的结构
请求(Request)
Request
•Reqeust(是个 struct),代表了客户端发送的 HTTP 请求消息
•重要的字段:
•URL
•Header
•Body
•Form、PostForm、MultipartForm
•也可以通过 Request 的方法访问请求中的 Cookie、URL、UserAgent 等信息
•Request 即可代表发送到服务器的请求,又可代表客户端发出的请求
请求的 URL
•Request 的 URL 字段就代表了请求行(请求信息第一行)里面的部分内容
•URL 字段是指向 url.URL 类型的一个指针,url.URL 是一个 struct:
type URL struct {
Scheme string
Opaque string
User *Userinfo
Host string
Path string
RawQuery string
Fragment string
}
url的通用形式
•通用格式是:scheme://[userinfo@]host/path[?query][#fragment]
•不可以斜杠开头的 URL 被解释为:scheme:opaque[?query][#fragment]
URL Query
•RawQuery 会提供实际查询的字符串。
•例如: http://www.example.com/post?id=123&thread_id=456
•它的 RawQuery 的值就是 id=123&thread_id=456
•r.URL.Query(),会提供查询字符串对应的 map[string][]string
•还有一个简便方法可以得到 Key-Value 对:通过 Request 的 Form 字段(以后再说)
// r.URL.RawQuery 会提供实际查询的原始字符串
// r.URL.Query() 会提供查询字符串对应的map[string][]string
// query = r.URL.Query()
// query[""] 返回[]string
// query.Get("") 返回 string 且只能获得第一个
http.HandleFunc("/query",func(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
id := query["id"]
log.Println(id)
name:= query.Get("name")
log.Println(name)
})
http.ListenAndServe("localhost:8080",nil)
// http://localhost:8080/query?id=123&name=456
// 2023/04/18 20:57:01 [123]
// 2023/04/18 20:57:01 456
// http://localhost:8080/query?id=123&name=hello&id=456&name=zcy
// 2023/04/18 20:58:25 [123 456]
// 2023/04/18 20:58:25 hello 看这里,只返回了第一个值 hello
url fragment
•如果从浏览器发出的请求,那么你无法提取出 Fragment 字段的值
•浏览器在发送请求时会把 fragment 部分去掉
// http://localhost:8080/url#hello 什么也没有输出
// 浏览器自动过滤了Fragment的部分
server:= http.Server{
Addr: "localhost:8080",
}
http.HandleFunc("/url",func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w,r.URL.Fragment)
})
server.ListenAndServe()
但不是所有的请求都是从浏览器发出的(例如从 HTTP 客户端包)
request header
•请求和响应(Request、Response)的 headers 是通过 Header 类型来描述的,它是一个 map,用来表述 HTTP Header 里的 Key-Value 对。
•Header map 的 key 是 string 类型,value 是 []string
•设置 key 的时候会创建一个空的 []string 作为 value,value 里面第一个元素就是新 header 的值;
为指定的 key 添加一个新的 header 值,执行 append 操作即可
// Request Header例子
// Header 是个map[string][]string
// r.Header 返回map
// r.Header[""] 返回[]string 类型
// r.Header.Get("") 返回string类型,把东西拼一起了。
http.HandleFunc("/header",func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w,r.Header)
fmt.Fprintln(w,r.Header["Accept-Encoding"])
fmt.Fprintln(w,r.Header.Get("Accept-Encoding"))
})
request body
请求和响应的 bodies 都是使用 Body 字段来表示的
Body 是一个 io.ReadCloser 接口
一个 Reader 接口
一个 Closer 接口
Reader 接口定义了一个 Open 方法:
参数:[]byte
返回:byte 的数量、可选的错误
Closer 接口定义了一个 Close 方法:没有参数,返回可选的错误
想要读取请求 body 的内容,可以调用 Body 的 Read 方法
http.HandleFunc("/post",func(w http.ResponseWriter, r *http.Request) {
length:= r.ContentLength
body := make([]byte,length)
r.Body.Read(body)
fmt.Fprintln(w,string(body))
})
表单form
通过表单发送请求
HTML 表单里面的数据会以 name-value 对的形式,通过 POST/GET请求发送出去。
它的数据内容会放在 POST 请求的 Body 里面
但 name-value 对在 Body 里面的格式是什么样的?
通过 POST 发送的 name-value 数据对的格式可以通过表单的 Content Type 来指定,也就是 enctype 属性
表单的enctype 属性
默认值是:application/x-www-form-urlencoded
浏览器被要求至少要支持: application/x-www-form-urlencoded 、multipart/form-data
HTML 5 的话,还需要支持 text/plain
如果 enctype 是 application/x-www-form-urlencoded,那么浏览器会将表单数据编码到查询字符串里面。
- 例如:
first_name=sau%20sheong&last_name=chang
- 例如:
如果 enctype 是 multipart/form-data,那么每一个 name-value 对都会被转换为一个MIME消息部分。每一个部分都有自己的 Content Type 和 Content Disposition
------WebKitFormBoundaryMPNjkpe09LiocMw
Content-Disposition:form-data;name="first_name"
sau sheong
------WebKitFormBoundaryMPNjkpe09LiocMw
Content-Disposition:form-data;name="last_name"
chang
------WebKitFormBoundaryMPNjkpe09LiocMw --
- 如何选择
- 简单文本:表单 URL 编码
大量数据,例如上传文件:multipart-MIME
甚至可以把二进制数据通过选择 Base64 编码,来当作文本进行发送
表单的GET
通过表单的 method 属性,可以设置 POST 还是 GET。GET 请求没有 Body,所有的数据都通过 URL 的 name-value 对来发送
Form 字段
- Request 上的函数允许我们从 URL 或/和 Body 中提取数据,通过这些字段:
- Form
- PostForm
- MultipartForm
- Form 里面的数据是 key-value 对。
通常的做法是: - 先调用 ParseForm 或ParseMultipartForm 来解析 Request
- 然后相应的访问 Form、PostForm 或 MultipartForm 字段
r.ParseForm()
// Form 取表单和url里面的
// 只支持 application/x-www-form-urlencoded
fmt.Fprintln(w,r.Form)
PostForm 字段
- 如果表单和 URL 里有同样的 Key,那么它们都会放在一个 slice 里:表单里的值靠前,URL 的值靠后
- 如果只想要表单的 key-value 对,不要 URL 的,可以使用PostForm 字段。
- PostForm 只支持 application/x-www-form-urlencoded
- 想要得到 multipart key-value 对,必须使用 MultipartForm 字段
r.ParseForm()
// PostForm 只取表单里面的
// 只支持 application/x-www-form-urlencoded
fmt.Fprintln(w,r.PostForm)
MultipartForm 字段
- 想要使用 MultipartForm 这个字段的话,首先需要调用 ParseMultipartForm 这个方法
- 该方法会在必要时调用 ParseForm 方法
- 参数是需要读取数据的长度
- MultipartForm 只包含表单的 key-value 对。返回类型是一个 struct 而不是 map。这个 struct 里有两个 map:
- key 是 string,value 是 []string
- key 是 string,value 是文件
r.ParseMultipartForm(1024)
//需要传入数据长度,字节数
fmt.Fprintln(w,r.MultipartForm)
// 返回的是个结构体,里面有两个map
// 第一个map[string][]string
// 第二个map[string]文件
FormValue & PostFormValue 方法
- FormValue 方法会返回 Form 字段中指定 key 对应的第一个 value
- 无需调用 ParseForm 或 ParseMultipartForm
- PostFormValue 方法也一样,但只能读取 PostForm
- FormValue 和 PostFormValue 在需要时都会调用ParseMultipartForm 方法
- 但如果表单的 enctype 设为 multipart/form-data,那么即使你调用ParseMultipartForm 方法,也无法通过 FormValue 获得想要的值。
- 只支持 application/x-www-form-urlencoded
// FormValue PostFormValue可以直接使用,无需解析,
// 且只返回一个值
// 注意!如果是 application/x-www-form-urlencoded
// FormValue可以带上url里的,但如果form和url的重名
// 会显示form的,因为它靠前
// PostFormValue 不能带上url里的
// 如果不小心用了multipart/form-data 应该是解析不了form 只能显示url里的。
multipart/form-data
- multipart/form-data 最常见的应用场景就是上传文件
- 首先调用 ParseMultipartForm 方法
- 从 File 字段获得 FileHeader,调用其 Open 方法来获得文件
- 可以使用 ioutil.ReadAll 函数把文件内容读取到 byte 切片里
r.ParseMultipartForm(1024)
fileHeader := r.MultipartForm.File["uploaded"][0]
//"uploaded" 是 file 的input标签的名字
file,err := fileHeader.Open()
if err == nil{
data,err := ioutil.ReadAll(file)
if err ==nil{
fmt.Fprintln(w,string(data))
}
}。
FormFile 方法
-- 上传文件还有一个简便方法:FormFile(例子)
-- 无需调用 ParseMultipartForm 方法
-- 返回指定 key 对应的第一个 value
-- 同时返回 File 和 FileHeader,以及错误信息
-- 如果只上传一个文件,那么这种方式会快一些
file,_,err := r.FormFile("uploaded")
if err == nil{
data,err := ioutil.ReadAll(file)
if err ==nil{
fmt.Fprintln(w,string(data))
}
}
POST JSON
-- 不是所有的 POST 请求都来自 Form
-- 客户端框架(例如 Angular 等)会以不同的方式对 POST 请求编码:
-- jQuery 通常使用 application/x-www-form-urlencoded
-- Angular 是 application/json
-- ParseForm 方法无法处理 application/json
MultipartReader()
func (r Request) MultipartReader() (multipart.Reader, error)
- 如果是 multipart/form-data 或 multipart 混合的 POST 请求:
- MultipartReader 返回一个 MIME multipart reader
- 否则返回 nil 和一个错误
- 可以使用该函数代替 ParseMultipartForm 来把请求的 body 作为 stream 进行处理
- 不是把表单作为一个对象来处理的,不是一次性获得整个 map
- 逐个检查来自表单的值,然后每次处理一个
小结
支持url编码的:
Form PostForm FormValue PostFormValue
支持 Multipart编码的:
MutipartForm
他们都支持表单键值对,但是只有Form 和FormValue 可以显示URL键值对
GO web学习(一)的更多相关文章
- Java Web 学习路线
实际上,如果时间安排合理的话,大概需要六个月左右,有些基础好,自学能力强的朋友,甚至在四个月左右就开始找工作了.大三的时候,我萌生了放弃本专业的念头,断断续续学 Java Web 累计一年半左右,总算 ...
- Web学习之css
CSS指层叠样式表(Cascading Style Sheets),CSS 是标准的布局语言,用来控制元素的尺寸.颜色.排版.CSS 由 W3C 发明,用来取代基于表格的布局.框架以及其他非标准的表现 ...
- web学习第一章
web学习第一章 我是大概9月10日开始走上IT之路的,一开始学习了小段时间的自动化办公软件, 昨天我开始学习客户端网页编程,我了解什么是WEB,一些比较老古董的计算模式和发展历史,印象最让我深刻 ...
- [原创]java WEB学习笔记95:Hibernate 目录
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问
本篇内容还是建立在上一篇Java Web学习系列——Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Jar包 这 ...
- Java Web学习系列——Maven Web项目中集成使用Spring
参考Java Web学习系列——创建基于Maven的Web项目一文,创建一个名为LockMIS的Maven Web项目. 添加依赖Jar包 推荐在http://mvnrepository.com/.h ...
- Java web 学习之旅
java web学习之旅 来公司十天了,感觉已经慢慢地融入了这个环境中,几个学长人都很好,都是在他们帮助下,我才能比较顺利的开始了学习java web的旅途. 来这里学习的第一个阶段是做一个简单的用户 ...
- [原创]java WEB学习笔记75:Struts2 学习之路-- 总结 和 目录
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- [原创]java WEB学习笔记66:Struts2 学习之路--Struts的CRUD操作( 查看 / 删除/ 添加) 使用 paramsPrepareParamsStack 重构代码 ,PrepareInterceptor拦截器,paramsPrepareParamsStack 拦截器栈
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- java web 学习笔记 编码问题总结
java web 学习笔记 编码问题总结 1.非form表单中提交的中文参数---------------------------传递给Servlet服务器时,默认以iso-8859-1解码 ...
随机推荐
- MySQL(十二)索引使用的情况分析
索引使用的情况分析 数据准备 创建表student_info.course CREATE TABLE `student_info` ( `id` int NOT NULL AUTO_INCREMENT ...
- 飞腾CPU FT-2000/4 uboot下PHY调试记录
飞腾爱好者技术交流群码公众号"乌拉大喵喵" 一.环境说明 板子是FT-2000/4的开发板: 固件版本: ft-2004c_u-boot-v2-Ver0.3_20211223100 ...
- AspNetCoreRateLimit应用于MVC项目求助
AspNetCoreRateLimit应用于MVC项目求助 前言 之前发过一篇文章: .NET Core WebApi接口ip限流实践 - 妙妙屋(zy) - 博客园 (cnblogs.com) 然后 ...
- 2022-07-23:给定N件物品,每个物品有重量(w[i])、有价值(v[i]), 只能最多选两件商品,重量不超过bag,返回价值最大能是多少? N <= 10^5, w[i] <= 10^5, v
2022-07-23:给定N件物品,每个物品有重量(w[i]).有价值(v[i]), 只能最多选两件商品,重量不超过bag,返回价值最大能是多少? N <= 10^5, w[i] <= 1 ...
- 2022-04-02:你只有1*1、1*2、1*3、1*4,四种规格的砖块。 你想铺满n行m列的区域,规则如下: 1)不管那种规格的砖,都只能横着摆, 比如1*3这种规格的砖,3长度是水平
2022-04-02:你只有11.12.13.14,四种规格的砖块. 你想铺满n行m列的区域,规则如下: 1)不管那种规格的砖,都只能横着摆, 比如1*3这种规格的砖,3长度是水平方向,1长度是竖直方 ...
- select_related和prefetch_related函数
在数据库存在外键的其情况下,使用select_related()和prefetch_related()很大程度上减少对数据库的请求次数以提高性能 在表中查找数据的时候,使用外键表related_nam ...
- 开发者一定要知道的 API 管理五大趋势
API First 大势所趋,APIaaS(API 作为服务)也将受到越来越多企业和组织的选择,研发团队对 API 研发管理工具的要求也水涨船高. API 在今天的数字化世界中扮演着至关重要的角色,随 ...
- drf——序列化之source(了解)、定制字段的两种方式(重要)、多表关联反序列化保存、反序列化字段校验、ModelSerializer使用
1 序列化高级用法之source(了解) # 1.创建了5个表(图书管理的5个) # 2.对book进行序列化 # 总结:source的用法 1.修改前端看到的字段key值--->source指 ...
- JSPModel
JSPModel what JSP开发模型就是JSP Model,是用JSP语言写的 why 为了更好地使用jsp技术开发 How JSPModel1 Why 因为在jsp开发中,包含了数据处理/业务 ...
- LeetCode 周赛 346(2023/05/21)仅 68 人 AK 的最短路问题
本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. LeetCode 单周赛第 345 场 · 体验一题多解的算法之美 单周赛 345 概览 T1. 删除子串后 ...