怎么调用获取被创建的预制体_Go 语言 Web 编程系列—— 获取用户请求数据(上)...

0、GET/POST 请求数据

在 PHP 中,可以直接通过全局变量 $_GET$_POST 快速获取 GET/POST 请求数据,GET 请求数据主要是 URL 查询字符串中包含的参数,以前面在线论坛项目的群组详情页为例:

http://localhost:8080/thread/read?id=adb02107-d7c3-4f27-4de4-b586f231380e

上述 URL 请求中的 id=adb02107-d7c3-4f27-4de4-b586f231380e 就属于 GET 请求数据,也就是查询字符串,而对于用户登录表单:

b5f00207d92a2be4780bc7244ab36345.png

当用户输入注册邮箱和密码后点击「登录」按钮,会将输入框中的数据作为请求实体发送 POST 请求到服务端,执行登录认证,这里的表单数据就是 POST 请求数据,如果我们查看表单请求路由的 HTTP 报文:

1b0497dff0fbccaa936288d3c803b3fc.png

就会看到表单请求数据,也就是上文提到的 HTTP 请求实体。

当然根据对服务端资源的操作类型不同,可以进一步细分为 POST、PUT、PATCH、DELETE 等包含请求实体的请求方法,为了简化模型,我们这里只讨论 POST 请求,而且其他几种请求方法也可以统一通过 POST 请求完成,通常只有在设计遵循 RESTful 风格的 API 接口时,才会严格划分不同的请求方法,关于这一点,后面介绍 REST + JSON 接口时再详细讨论。

1、Form

Go 语言中获取用户请求数据的方式要更复杂一些,Go 也为此提供多个不同的结构体帮助我们读取不同请求类型的数据,首先,我们可以通过请求对象上的 Form 读取所有 GET/POST 请求数据,在 handlers/post.go 中新增 EditPost 方法如下:

func EditPost(w http.ResponseWriter, r *http.Request)  {
    r.ParseForm()
    fmt.Fprintln(w, r.Form)
}

需要注意的是,在通过 r.Form 获取所有请求数据之前,必须要先通过 r.ParseForm() 解析所有请求数据,否则无法获取数据。

routes/web.go 中新增一个路由:

WebRoute{
    "UpdatePost",
    "POST",
    "/post/edit",
    handlers.EditPost,
},

然后我们重启 HTTP 服务器,在命令行通过 curl 发起一个包含不同类型请求数据的请求:

1cea223052e211404007059e61be1211.png

可以看到,打印结果表明 r.Form 是一个包含所有请求数据的字典类型(map),包含 URL 查询字符串和 POST 请求数据,这是一个 POST 请求,如果是 GET 请求呢?我们为 EditPost 定义一个 GET 请求路由:

WebRoute{
    "EditPost",
    "GET",
    "/post/edit",
    handlers.EditPost,
},

再重启 HTTP 服务器,发起一个只包含查询字符串的 GET 请求(默认是 GET 请求,不需要通过 -X GET 指定):

e9241314fc573724348f278d8b9b053e.png

同样可以打印出和 POST 请求完全一样的结果。

因此,request 对象上的 Form 可以获取所有请求参数,包括查询字符串和请求实体,并且不限请求类型。如果你想要进一步要获取指定的参数值,可以以索引方式获取指定参数对应的值,也可以通过 Form 提供的 Get 方法,就像我们从一个普通字典类型获取键值一样:

id1 := r.Form["id"]
id2 := r.Form.Get("id")
fmt.Println(id1)
fmt.Println(id2)

只不过两者的返回值类型不一样,前者是一个字符串切片,后者是一个字符串值:

[1]
1

2、PostForm

上面的结果同时返回了查询字符串和请求实体,如果只想获取请求实体(即 POST 表单中的数据),可以通过 PostForm 实现:

func EditPost(w http.ResponseWriter, r *http.Request)  {
    r.ParseForm()
    id := r.Form.Get("id")
    fmt.Println("post id:", id)
    fmt.Println("form data:", r.PostForm)
    io.WriteString(w, "表单提交成功")
}

这样一来,就只能获取到 POST 数据了:

4d9cd831fd3294591ae36c4199f782f8.png

然后在 HTTP 服务器日志,可以看到如下答应结果:

433f0c2a0af03220ae5e462af5b2b9f4.png

可以看到 r.PostForm 返回的也是字典类型数据,数据格式和 r.Form 完全一致,并且这次只包含了 POST 表单请求数据,不包含 URL 查询字符串,也就是说,通过 r.PostForm 只能获取 POST 请求数据(请求实体数据),无法获取 GET 请求数据(查询字符串中的数据),你可以再次发起 GET 请求进行验证:

53a1829536c0beaa45e38b9e27542b0c.png

这个时候,可以看到服务器打印日志之包含 id 信息,表单信息为空:

2a0b30ee23d876bfe99d48b30484534c.png

通过 PostForm 获取具体参数值的方式和 Form 一样,这里就不再赘述了:

title := r.PostForm.Get("title")
content := r.PostForm.Get("content")

实际上,我们在前面的在线论坛项目中,就是通过这个方式获取表单请求数据的:

err := request.ParseForm()
user, err := models.UserByEmail(request.PostFormValue("email"))

3、FormValue/PostFormValue

最后,还可以通过 FormValuePostFormValue 获取用户请求数据,使用它们的好处是不再需要单独调用 ParseForm 对表单数据进行解析,不过使用这两个方法的时候只能获取特定请求数据,不能一次获取所有请求数据:

func EditPost(w http.ResponseWriter, r *http.Request)  {
    fmt.Println("post id:", r.FormValue("id"))
    fmt.Println("post title:", r.PostFormValue("title"))
    fmt.Println("post title:", r.PostFormValue("content"))
    io.WriteString(w, "表单提交成功")
}

FormValue/PostFormValue 的区别和 Form/PostForm 一样,这里通过命名就可以看出来,前者可以获取所有 GET/POST 请求数据(即查询字符串和请求实体),后者只能获取 POST 请求实体数据。

注:FormValue/PostFormValue 之所以不用显式调用 ParseForm 解析请求数据,是因为底层对其进行了封装,实际上还是要调用这个方法。

4、获取 JSON 请求数据

上面的示例默认都是基于 HTML 表单请求,对于客户端提交的 JSON 格式数据,使用 ParseForm 是无法解析并获取数据的,因为 HTML 表单请求数据默认是通过 application/x-www-form-urlencoded 编码的,而 JSON 请求数据通常是通过 application/json 编码,ParseForm 只能解析通过 application/x-www-form-urlencoded 编码的数据。

对于 JSON 请求数据的解析,目前我们可以通过上篇教程介绍的,读取完整请求实体并进行 JSON 解码实现,下面我们改写 AddPost 方法实现如下:

type Post struct {
    Title string `json:"title"`
    Content string `json:"content"`
}

func AddPost(w http.ResponseWriter, r *http.Request)  {
    len := r.ContentLength   // 获取请求实体长度
    body := make([]byte, len)  // 创建存放请求实体的字节切片
    r.Body.Read(body)        // 调用 Read 方法读取请求实体并将返回内容存放到上面创建的字节切片
    // io.WriteString(w, string(body))
    post := Post{}
    json.Unmarshal(body, &post)  // 对读取的 JSON 数据进行解析
    fmt.Fprintf(w, "%#v\n", post)   // 格式化输出结果
}

我们将读取的请求实体数据通过 JSON 解码映射到 Post 结构体对象并将其输出到响应结果。

重启 HTTP 服务器,通过 curl 模拟客户端提交 JSON 请求数据:

3aad59d29c8f652375e2bb6104681bca.png

我们通过 -H 选项指定请求数据编码格式为 application/json,然后请求数据调整为 JSON 格式字符串,最后通过输出结果可以看到在服务端 JSON 请求数据已经可以成功解析并获取。

5、小结

到这里,我们已经了解了在 Go Web 编程中,常见的用户请求数据如何解析并获取(URL 查询字符串、POST 表单数据、JSON 请求数据),实际上,和 PHP 中的 $_GET$_POST 类似,Go 也是将 HTTP 请求数据映射到请求对象对应的结构体,然后开发者可以从上下文请求对象中解析并读取这些请求数据,使用这些封装好的对象的好处是它们屏蔽了底层的细节,统一了数据格式,可以大大提高开发效率,减少不必要的数据格式兼容成本。

下篇教程,学院君将给大家介绍如何从表单请求中获取文件数据,并实现简单的文件上传功能。

(全文完)

推荐阅读

  • Go 语言 Web 编程系列 —— 通过 Request 读取 HTTP 请求报文


喜欢本文的朋友,欢迎关注“Go语言中文网”:

bab511465d3c0be9154a0c1ee2f064ac.png

Go语言中文网启用微信学习交流群,欢迎加微信:274768166,投稿亦欢迎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/339842.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

删除表报正在使用_U盘拔出要不要点quot;安全删除USB硬件quot;退出?

小U盘,大用处。U盘不仅可以用来存储各种各样的文件,甚至还可以用来制作电脑启动盘、Win to Go系统盘等。直接拔还是点“安全删除”后再拔U盘呢?在用完U盘后,有的会点击电脑右下角“安全删除”才拔,有的则会不管那么多直…

职业规划测试软件,生涯规划常用测试工具

原标题:生涯规划常用测试工具认识自己测试生涯规划关于生涯规划的几个测试上周我们说到中学生很有必要进行生涯规划,在进行生涯规划前,我们需要对自己有一个更清晰、更全面的认识,随着心理学的发展,很多认识自我的测试…

使用SoapUI调用不同的安全WCF SOAP服务-基本身份验证,第一部分

在这个分为三部分的系列中,我将演示如何使用SoapUI API工具来调用安全的WCF SOAP服务。 第一篇文章将着重于创建将要测试的系统的服务。 第二篇文章将介绍在基本身份验证机制保护的情况下调用它所需的步骤。 在最后一部分中,我将对初始服务稍作更改&…

配置中文_星球大战:战机中队配置需求公布 支持中文

近日《星球大战》系列新作《星球大战:战机中队》公布,该作采用寒霜引擎打造,支持中文。游戏将于2020年10月3日发售,预购价格为238元,登陆Xbox One/PS4/PC(Steam/Origin/Epic)平台,有单人和多人模式&#xf…

为什么在生产中进行硒自动化测试对于您的下一个版本至关重要?

您是否认为仅仅是因为您的Web应用程序在过渡环境中以鲜艳的色彩通过了,您的生产环境也将是相同的吗? 您可能需要重新考虑! 特别是,如果我们指的是跨浏览器测试 ,则需要确保跨各种操作系统,运行在不同操作系…

手机usb共享计算机网络连接,如何将手机wifi网络通过USB共享给电脑?小编教你共享方法...

曾经就有过这样的情况,家里突然断网了,这时又需要打开电脑接收文件,或是需要在线编辑公众号的文章,着急得很,这时电脑没有网络怎么办呢?能不能使用手机的流量,来让电脑连网呢?有时候…

为全局变量赋值_实例分析如何远离漫天飞舞的全局变量

前篇《由static来谈谈模块封装》基本实现了对外隐藏属性,隐藏局部模块函数,开放接口的功能。对于这个话题还有些点没有深入探讨:为什么要这样做?以及这样做的好处。或许很多刚刚开始用C或者其他面向对象编程语言(比如C)的小伙伴们…

计算机指令取决,不同的计算机,其指令不同,这主要取决于什么?

不同的计算机,其指令系统也不同,这主要取决于所用的CPU。1、CPU指中央处理器,是一块超大规模的集成电路,是一台计算机的运算核心(Core)和控制核心( Control Unit)。它的功能主要是解释计算机指令以及处理计算机软件中的数据。2、程…

栈空间_Linux中的进程栈和线程栈

1. 进程栈进程栈是属于用户态栈,和进程虚拟地址空间 (Virtual Address Space) 密切相关。那我们先了解下什么是虚拟地址空间:在 32 位机器下,虚拟地址空间大小为 4G。这些虚拟地址通过页表 (Page Table) 映射到物理内存,页表由操作…

csgo显示服务器失败,csgo服务器失败

csgo服务器失败 内容精选换一换您可以通过“应用管理”页面的应用列表,快速查看应用状态,及相关异常信息,如图1所示。包括:应用状态:即图1中的①应用异常信息:即图1中的②云服务器异常信息:即图…

DMN中的函数式编程:感觉就像再次重读我的大学课程一样

在本文中,我想分享有关DMN中的递归支持的有趣见解,并重点介绍FEEL语言的特定属性如何使功能编程结构能够在DMN中建模。 我们将从一个基本的示例开始,以演示FEEL语言和DMN构造的“商业友好”性质如何使我们能够解决一个通常不愉快的问题&…

手游极品飞车无限狂飙链接服务器失败,极品飞车无极限无法联网是什么原因 联网失败原因分析及解决方法...

有些玩家对于极品飞车无极限游戏中无法联网的问题而困扰,应该怎么解决呢?下面42824小小编就把方法分享给大家!一、极品飞车无极限游戏无法联网原因及解决方法1、网络连接不稳定推荐在wifi的情况下进行游戏,如果是3G网的话很容易会…

mysql中创建唯一索引的关键字_mysql中唯一索引的关键字是什么

mysql中唯一索引的关键字是unique index。创建唯一索引可以避免数据出现重复。唯一索引可以有多个,但索引列的值必须唯一,索引列的值允许有空值。创建唯一索引可以使用关键字UNIQUE随表一同创建。mysql中唯一索引的关键字是unique index。(推荐教程&…

奇迹觉醒qq服务器比微信少,十年内最大的奇迹!功能比QQ还少的微信为什么能成功?...

今天,微信迎来了自己2021年的第一次「翻车」——2021年1月18日下午2点前后,「由于系统抖动原因」部分微信用户无法及时收取微信消息。截止下午3点19分,故障已被修复。其实微信曾面临过几次信息服务中断的事故:2013年,微…

linux终止mysql进程_Ubuntu Linux下定时监测MySQL进程终止时自动重启的方法

前言最近发现MySQL服务隔三差五就会挂掉,导致我的网站和爬虫都无法正常运作。自己的网站是基于MySQL,在做爬虫存取一些资料的时候也是基于MySQL,数据量一大了,MySQL它就有点受不了了,时不时会崩掉,虽然我自…

线性搜索或顺序搜索算法在Java中如何工作? 示例教程

大家好,我之前谈到了二进制搜索算法的工作原理,并分享了在Java中实现二进制搜索的代码。 在那篇文章中,有人问我是否还存在其他搜索算法? 如果数组中的元素未排序,又如何使用二进制搜索算法,该如何搜索呢&a…

mysql server 5.0安装教程_MySQL Server 5.0安装教程

运行MySQL Server 5.0安装程序“setup.exe”,出现如下界面:安装向导启动,按“Next”继续:选择安装类型,为了方便熟悉安装过程,我们选择“Custom”。按“Next”继续:在“Developer Components”上…

hibernate jpa_JPAHibernate替代方案。 如果JPA或Hibernate对于我的项目而言不够好,该怎么办?...

hibernate jpa你好!你好吗? 今天我们将讨论不建议使用JPA / Hibernate的情况。 在JPA领域之外,我们还有哪些选择? 我们将谈论的是: JPA /Hibernate问题 解决一些JPA /Hibernate问题的方法 选择此处描述的框架的标准…

约束流–没有Drools规则语言的现代Java约束

传统上,要使用OptaPlanner进行扩展,您必须学习DRL。 不再。 借助受Java 8 Streams和SQL启发的新Constraints Streams API,您现在可以用Java (或Kotlin或Scala) 编写约束,并且仍然可以从增量计算中受益。 在…

mysql数据库杀掉堵塞_Mysql解决USE DB堵塞详解

遇到故障,我们往往想的是如何解决这个故障,而不是从故障的根本去思考出现这个故障的原因?这样的结果,只能使我们得到了鱼,失去了渔。今天,我们就来分享一个由USE DB堵塞故障引发的思考案例。故障描述今天一…