GVKun编程网logo

Go 语言(十三)Gin Web 框架(go语言的web框架)

1

在这篇文章中,我们将为您详细介绍Go语言的内容,并且讨论关于十三GinWeb框架的相关问题。此外,我们还会涉及一些关于asp.net-web-api–System.Web.Routing.RouteC

在这篇文章中,我们将为您详细介绍Go 语言的内容,并且讨论关于十三Gin Web 框架的相关问题。此外,我们还会涉及一些关于asp.net-web-api – System.Web.Routing.RouteCollection不包含“MapHttpRoute”的定义 – VS 2012,Web API、asp.net-web-api – 在ASP.NET Web API控制器的nunit测试中实例化新的System.Web.Http.OData.Query.ODataQueryOptions、AutoTLS 和 Gin (gin-gonic) 无法读取 SSL 证书、Gin Web 应用程序仅渲染一个模板的知识,以帮助您更全面地了解这个主题。

本文目录一览:

Go 语言(十三)Gin Web 框架(go语言的web框架)

Go 语言(十三)Gin Web 框架(go语言的web框架)

简介

  • 基于 httprouter 开发的 web 框架:https://github.com/gin-gonic/gin
  • 提供 Martini 风格的 API,但比 Martini 要快 40 倍
  • 非常轻量级,使用简洁

Gin 框架的安装与使用

  • 安装: go get -u github.com/gin-gonic/gin

    基本使用

import "github.com/gin-gonic/gin"

func main() {
   r := gin.Default()
   r.GET("/ping", func(c *gin.Context) {
      c.JSON(200, gin.H{
         "message": "pong",
      })
   })
   r.Run("0.0.0.0:9090")
}

支持 restful 风格的 API

  • 把设计的 API 抽象成一个个资源,用 URI 来标识
  • 针对每一个资源,使用统一的方法进行操作
  • 统一的方法: GET,POST,PUT,DELETE
import (
   "github.com/gin-gonic/gin"
   "net/http"
)

type Result struct {
   Message string   `json:"message"`
   Code    int      `json:"code"`
}

func handleUserInfo(c *gin.Context) {
   var result Result = Result{
      Message: "hello",
      Code:    0,
   }
   c.JSON(http.StatusOK,result)
}

func main() {
   r := gin.Default()
   r.GET("/user/info", handleUserInfo)
   r.Run("0.0.0.0:9090")
}

queryString 设计

  • 查询类:http://127.0.0.1:9090/user/info?username=dadasd&&passwd=1234
  • 路由类:http://127.0.0.1:9090/user/info/2020/12
import (
   "github.com/gin-gonic/gin"
   "net/http"
)

type Result struct {
   Message string   `json:"message"`
   Code    int      `json:"code"`
}

type UserInfo struct {
   Result
   UserName  string   `json:"username"`
   Passwd string      `json:"passwd"`
}

func handleUserParams(c *gin.Context) {
   //查询类接口
   username := c.Query("username")
   passwd := c.DefaultQuery("passwd","adcdefg")

   var result UserInfo = UserInfo{
      Result{
         Message: "success",
         Code:    200,
      },
      username,
      passwd,
   }
   c.JSON(http.StatusOK,result)
}

func handleUserInfo(c *gin.Context) {
   //路由类接口
   username := c.Param("username")
   passwd := c.Param("passwd")

   var result UserInfo = UserInfo{
      Result{
         Message: "success",
         Code:    200,
      },
      username,
      passwd,
   }
   c.JSON(http.StatusOK,result)
}

func main() {
   r := gin.Default()
   r.GET("/user/info", handleUserParams)
   r.GET("/user/info/:username/:passwd", handleUserInfo)
   r.Run("0.0.0.0:9090")
}

Gin 框架参数传递

获取表单参数

import (
   "github.com/gin-gonic/gin"
   "net/http"
)

type Result struct {
   Message string   `json:"message"`
   Code    int      `json:"code"`
}

type UserInfo struct {
   Result
   UserName  string   `json:"username"`
   Passwd string      `json:"passwd"`
}

func handleUserInfo(c *gin.Context) {
   username := c.PostForm("username")
   passwd := c.PostForm("passwd")

   var result UserInfo = UserInfo{
      Result:   Result{
         Message: "success",
         Code: 200,
      },
      UserName: username,
      Passwd:   passwd,
   }
   c.JSON(http.StatusOK,result)
}

func main()  {
   r := gin.Default()
   r.POST("/user/info",handleUserInfo)
   r.Run(":9090")
}

单文件上传

郑州做试管婴儿多少钱:http://jbk.39.net/yiyuanfengcai/tsyl_zztjyy/3019/

func handleUpload(c *gin.Context) {
   file,err := c.FormFile("testfile")
   if err != nil {
      fmt.Printf("upload file faild,err:%v\n",err)
      return
   }

   //文件上传路径
   filename := fmt.Sprintf("/Users/wanghui/go/src/oldBoy/day8/tmp/%s",file.Filename)
   //文件保存
   err = c.SaveUploadedFile(file,filename)
   if err != nil {
      fmt.Printf("save file faild,err:%v\n",err)
      return
   }
   //状态返回
   c.JSON(http.StatusOK,"file upload success")
}

func main() {
   r := gin.Default()
   r.POST("/file/upload",handleUpload)
   r.Run(":9090")
}

多文件上传

func multiHandleUpload(c *gin.Context) {
   //多文件上传
   form,err := c.MultipartForm()
   if err != nil {
      fmt.Printf("upload file faild,err:%v\n",err)
      return
   }
   files := form.File["testfile"]

   for _,file := range files {
      filename := fmt.Sprintf("/Users/wanghui/go/src/oldBoy/day8/tmp/%s",file.Filename)
      err = c.SaveUploadedFile(file,filename)
      if err != nil {
         fmt.Printf("save file faild,err:%v\n",err)
         return
      }
   }
   //状态返回
   c.JSON(http.StatusOK,"file upload success")
}
func main() {
   r := gin.Default()
   r.POST("/file/upload",handleUpload)
   r.POST("/files",multiHandleUpload)
   r.Run(":9090")
}

通过 postman 上传文件
Go语言(十三)Gin Web框架

路由分组

func main()  {
   r := gin.Default()
   v1Group := r.Group("/v1")
   v1Group.POST("/user/info",handleUserInfo)
   v1Group.POST("/user/info2",handleUserInfo)
   r.Run(":9090")
}

gin 的参数绑定

  • 为什么要使用参数绑定
    • 通过反射的机制,自动提取 querystring、form 表单,json,xml 等参数到 struct 中
    • 通过 http 协议中的 content type,识别是 json,xml 或者表单
type UserInfo struct {
   UserName  string  `form:"username" json:"username" binding:"required"`
   Passwd    string  `form:"passwd" json:"passwd" binding:"required"`
   Age       int    `form:"age" json:"age" binding:"required"`
   Sex       string  `form:"sex" json:"sex" binding:"required"`
}

func PostUserInfo(c *gin.Context) {
   var UserInfo UserInfo
   //表单绑定,使用指针
   err := c.ShouldBind(&UserInfo)
   if err != nil {
      return
   }
   c.JSON(http.StatusOK,UserInfo)
}

func PostUserInfoJson(c *gin.Context) {
   var UserInfo UserInfo
   //表单绑定,使用指针
   err := c.ShouldBindJSON(&UserInfo)
   if err != nil {
      return
   }
   c.JSON(http.StatusOK,UserInfo)
}

func GetUserInfoJson(c *gin.Context) {
   var UserInfo UserInfo
   //表单绑定,使用指针
   err := c.ShouldBindJSON(&UserInfo)
   if err != nil {
      return
   }
   c.JSON(http.StatusOK,UserInfo)
}

func main() {
   r := gin.Default()
   v1Group := r.Group("/v1")
   v1Group.POST("/user/infos",PostUserInfo)
   v1Group.POST("/user/infojson",PostUserInfoJson)
   v1Group.GET("/user/info",GetUserInfoJson)
   r.Run(":9090")
}

渲染

  • gin.Context.JSON 方法进行渲染         郑州不孕不育医院哪里好:http://byby.tjyy120.com/
type UserInfo struct {
   UserName  string  `form:"username" json:"username" binding:"required"`
   Passwd    string  `form:"passwd" json:"passwd" binding:"required"`
}

func GetUserInfoJson(c *gin.Context) {
   var userInfo = &UserInfo{
      UserName: "zhansan",
      Passwd:   "aaaa",
   }
   c.XML(200,userInfo)
}

func main() {
   r := gin.Default()
   v1Group := r.Group("/v1")
   v1Group.GET("/user/info",GetUserInfoJson)
   r.Run(":9090")
}

HTML 模板渲染

  • templates/post.html
{{ define "index.tmpl" }}
    <html><h1>
        {{ . }}
    </h1>
    <p>Using posts/index.tmpl</p>
    </html>
{{ end }}
  • server.go
func HandleHtmml(c *gin.Context) {
   c.HTML(200,"index.tmpl","mmmmmmmm")
}

func main() {
   r := gin.Default()
   r.LoadHTMLGlob("./templates/*")
   r.GET("/user/info",HandleHtmml)
   r.Run(":9090")
}

gin 中间件

  • gin 框架在请求处理过程中,加入用户自己的钩子函数,这个钩子函数就叫做中间件
  • 因此,可以使用中间件处理一些公共业务逻辑,比如耗时统计,日志打印,登录校验等
func StatCost(c *gin.Context) {
   //中间件
   start := time.Now()
   fmt.Printf("start \n")
   c.Next()
   lattacy := time.Since(start)
   fmt.Printf("cost Time is %dms\n", lattacy/1000/1000)
}

func funcHello(c *gin.Context) {
   fmt.Printf("request start\n")
   time.Sleep(time.Second * 3)
   c.JSON(http.StatusOK, "hello world")
}

func main() {
   r := gin.Default()
   r.Use(StatCost)
   r.GET("/hello", funcHello)
   r.Run(":9090")
}

gin 框架路由原理

  • 路由部分使用的是:https://github.com/julienschmidt/httprouter
  • 对于路由的规则,httprouter 会构造一颗前缀树

Go语言(十三)Gin Web框架

asp.net-web-api – System.Web.Routing.RouteCollection不包含“MapHttpRoute”的定义 – VS 2012,Web API

asp.net-web-api – System.Web.Routing.RouteCollection不包含“MapHttpRoute”的定义 – VS 2012,Web API

我刚刚安装了Visual Studio 2012,并开始检查MVC 4和Web Api。
我已经用Web API创建了一个新的MVC 4应用程序。基于一些示例和教程,我开始配置我的路由:
routes.MapHttpRoute(
                name: "Controller only",routeTemplate: "api/{controller}"
            );

但是,这会导致RouteCollection不包含MapHttpRoute的定义的错误。我是否安装了一些DLL?
据我看到,我已经安装了所有正确的DLL和版本。

解决方法

我已经通过在RouteConfig.cs中添加对System.Web.Http的引用来解决它

asp.net-web-api – 在ASP.NET Web API控制器的nunit测试中实例化新的System.Web.Http.OData.Query.ODataQueryOptions

asp.net-web-api – 在ASP.NET Web API控制器的nunit测试中实例化新的System.Web.Http.OData.Query.ODataQueryOptions

我有一个ASP.NET MVC4 Web API项目与ApiController继承的控制器接受一个ODataQueryOptions参数作为其输入之一.

我正在使用NUnit和Moq来测试该项目,这使我能够从ApiController使用的相关的存储库方法中设置canned响应.这样做,如:

[TestFixture]
public class ProjectControllerTests
{
    [Test]
    public async Task GetById()
    {
        var repo = new Mock<IManagementQuery>();

        repo.Setup(a => a.GetProjectById(2)).Returns(Task.Fromresult<Project>(new Project()
        { 
              ProjectID = 2,ProjectName = "Test project",ProjectClient = 3
        }));

        var controller = new ProjectController(repo.Object);
        var response = await controller.Get(2);

        Assert.AreEqual(response.id,2);
        Assert.AreEqual(response.name,"Test project");
        Assert.AreEqual(response.clientId,3);
    }
}

我所面临的挑战是,要使用这种模式,我需要将相关的querystring参数传递给控制器​​以及存储库(这实际上是我的意图).然而,在使用ODataQueryOptions接受ApiController方法的情况下,即使在我想仅使用ODataQueryOptions的默认参数的情况下,我需要知道如何实例化一个.这变得棘手:

> ODataQueryOptions不实现接口,所以我不能直接模拟它.
>构造函数需要实现System.Web.Http.OData.ODataQueryContext,它需要实现一些实现Microsoft.Data.Edm.IEdmModel的文件,文档很少,Visual Studio 2012查找引用和查看调用层次不会提供洞察力(实现该接口?).

我需要做什么/有更好的方法吗?

谢谢.

解决方法

看来,其他人在 here的评论中已经回答了这个问题,但这不是我的用例的完整解决方案(见下面的评论):
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder(); 
modelBuilder.EntitySet<Customer>("Customers"); 
var opts = new ODataQueryOptions<Customer>(new ODataQueryContext(modelBuilder.GetEdmModel(),typeof(Customer)),request);

AutoTLS 和 Gin (gin-gonic) 无法读取 SSL 证书

AutoTLS 和 Gin (gin-gonic) 无法读取 SSL 证书

autotls 和 gin (gin-gonic) 无法读取 ssl 证书

php小编小新发现,当使用AutoTLS和Gin (gin-gonic)构建Web应用程序时,可能会遇到一个问题:无法读取SSL证书。这个问题可能会导致应用程序无法正常使用HTTPS协议进行安全通信。尽管AutoTLS和Gin都是非常流行的工具,但在处理SSL证书方面存在一些限制。在本文中,我们将深入探讨这个问题,并提供一些解决方案,以帮助开发者克服这个难题。

问题内容

我正在尝试使用 gin (gin-gonic) 用简单的代码创建一个微服务环境:

package main

import (
    "example.com/MSHandler/ms1"

    "log"

    "github.com/gin-gonic/autotls"
    "github.com/gin-gonic/gin"
)



func main() {
    // Create GIN
    router := gin.Default()

    // Call MS

    // Call MS1
    router.GET("/ms1", ms1.CallMS1)

    // Run GIN
    // router.Run(":443")

    // Run with Let''s Encrypt
    log.Fatal(autotls.Run(router, "exampleMS.org"))
}
登录后复制

每次我尝试访问该网站时,该网站都会被标记为不安全。我的 ssl 证书是使用 openssl 生成的,它们(.key 和 .pem)都位于 ~/.ssl 文件夹中(我使用的是 ubuntu)。我的证书需要与应用程序位于同一文件夹中吗?

我在网上和此处阅读了一些文章,但没有任何内容直接指向 autotls。

解决方法

软件包 github.com/gin-gonic/autotls 在下面使用 golang.org/x/crypto/acme/autocert 。因此,如果您想阅读该文档,请转到 https://pkg .go.dev/golang.org/x/crypto/acme/autocert。 Let''s Encrypt 的工作原理是必读文档。

注释

  1. autocert 从 https://www.php.cn/link/1c9884d82761f8718077f56cee0c1da4 应用证书,因此您不需要提供您自己使用 openssl 生成的证书。如果您想使用自签名证书,则不需要 autocert (和 autotls)。并且默认情况下,客户端不信任自签名证书。

  2. autocert 将为您创建一个新的 ECDSA P-256 密钥。如果您想使用自己的私钥,请使用 设置密钥autocert.Manager.

  3. 由于需要申请来自https://www.php.cn/link/1c9884d82761f8718077f56cee0c1da4的证书,公网应该可供您的应用程序使用。

  4. Let''s Encrypt 将通过向您的网站发送 HTTP 请求来验证您是否是域所有者。确保您的网站可以在域上访问(根据您的演示,它是 exampleMS.org)。并且这个请求发送到HTTP端口80。所以你应该确保这个端口也没有被阻止。更准确地说:

    Let’s Encrypt CA 将查看所请求的域名并发出一组或多组挑战。这些是代理证明域控制权的不同方式。例如,CA 可能会给代理一个选择:

    • 在 example.com 下配置 DNS 记录,或者
    • 在众所周知的 URI 下配置 HTTP 资源
  5. autotls提供了几个演示,如果你不知道的话。

以上就是AutoTLS 和 Gin (gin-gonic) 无法读取 SSL 证书的详细内容,更多请关注php中文网其它相关文章!

Gin Web 应用程序仅渲染一个模板

Gin Web 应用程序仅渲染一个模板

gin web 应用程序仅渲染一个模板

Gin是一款轻量级的Web框架,被广泛应用于Go语言的Web开发中。在Gin中,Web应用程序通常只需要渲染一个模板即可完成页面的展示。这种设计使得开发者可以更加专注于业务逻辑的实现,简化了开发流程。在php小编小新的观点中,Gin的这种特性不仅提高了开发效率,还能减少资源的占用,使得Web应用程序更加高效。同时,Gin还提供了丰富的中间件和插件,为开发者提供了更多的扩展性和灵活性。总之,Gin的简洁而强大的特性使得它成为了许多开发者的首选框架。

问题内容

我有一个 Gin Web 应用程序,其中包含基于一组部分和一个基本模板的多个 HTML 模板。基本模板似乎与相关部分一起渲染得很好,但我的主要视图、登录、索引和注册没有按预期渲染。每当我访问其中任何一个的 HTTP 端点时,只会呈现寄存器视图。

以下文件中缺少或配置错误的内容导致我的路由无法呈现请求的页面?

我的项目具有以下结构。

├── app
...
│   ├── handlers
│   │   ├── general
│   │   │   └── general.go
│   │   └── routes.go
│   ├── main.go
│   ├── reloadDev.sh
│   ├── static
│   │   ├── css
│   │   ├── img
│   │   └── js
│   └── templates
│       ├── home
│       │   ├── index.tmpl.html
│       │   ├── login.tmpl.html
│       │   └── register.tmpl.html
│       ├── layouts
│       │   └── base.tmpl.html
│       └── partials
│           ├── footer.tmpl.html
│           ├── head.tmpl.html
│           └── navbar.tmpl.html
登录后复制

base.tmpl.html

{{ define "base" }}
<!DOCTYPE html>
<html lang="eng" data-bs-theme="dark">
    {{ template "head" . }}
    {{template "navbar" .}}
    <body>
    {{ block "content" . }}{{ end }}
    </body>
    {{template "footer" .}}
</html>
{{end}}
登录后复制

注册.tmpl.html

{{ template "base" . }}
{{ define "content" }}
<div>
    <div>
        <div>
            <h1>Register</h1>
            <form action="/register" method="post">
                <div>
                    <label for="username">Username</label>
                    <input type="text" name="username" id="username"placeholder="Username" required>
                </div>
                <div>
                    <label for="password">Password</label>
                    <input type="password" name="password" id="password"placeholder="Password" required>
                </div>
...SNIP...
                <button type="submit">Register</button>
            </form>
        </div>
    </div>
</div>
{{ end }}
登录后复制

index.tmpl.html(登录的结构与这两个相同。)

{{ template "base" . }}
{{ define "title" }}Home{{ end }}
{{ define "content" }}
<div>
    <div>
        <div>
            <p>Welcome to Astra Porta.</p>
            <p>Click <a href="https://www.php.cn/link/1b8e84dcae97ad25234484e38615c570">here</a> to login.</p>
        </div>
    </div>
</div>
{{ end }}
登录后复制

HTML 模板使用 embed.FS 与二进制文件捆绑在一起。

//go:embed templates/partials/* templates/layouts/* templates/home/*
var files embed.FS

func main() {
    router := setupRouter()
    err := router.Run()
    if err != nil {
        panic(err)
    }
}

func setupRouter() *gin.Engine {
    router := gin.Default()
    subFS, e := fs.Sub(files, "templates")
    if e != nil {
        panic(e)
    }

tmpl := template.Must(template.ParseFS(
    subFS,
    "layouts/*.html",
    "partials/*.html",
    "home/*.html",
))
router.SetHTMLTemplate(tmpl)

router.StaticFS("/static", http.Dir("static"))

err := router.SetTrustedProxies(nil)
if err != nil {
    panic(err)
}
handlers.InitializeRoutes(&router.RouterGroup)
return router
}
登录后复制

页面在我的应用程序路由中呈现。此处的引用映射到 *.tmpl.html 文件的文件名。

func SiteIndex(c *gin.Context) {
    c.HTML(http.StatusOK, "index.tmpl.html", nil)
}

func GetRegister(c *gin.Context) {
    c.HTML(http.StatusOK, "register.tmpl.html", nil)
}

func GetLogin(c *gin.Context) {
    c.HTML(http.StatusOK, "login.tmpl.html", nil)
}
登录后复制

解决方法

对于其他遇到此问题的人。 mkopriva 评论中指出的解决方案是正确的。我删除了 base.tmpl.html 并使用更新的部分和目标页面组成每个视图。

标题

{{ define "header" }}
<!DOCTYPE html>
<html lang="eng" data-bs-theme="dark">
{{template "navbar" .}}
    <body>
    {{ block "content" . }}{{ end }}
        <head><meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
           ...SNIP...
            <title>App</title>
        </head>
{{end}}
登录后复制

页脚

{{define "footer"}}

        <div>
            <footerdata-bs-theme="dark">
                <ul>
                    <li><a href="/">Home</a></li>
                </ul>
                <p>© 2024 .</p>
            </footer>
        </div>
    </body>
</html>
{{end}}
登录后复制

有问题的页面

{{template "header"}}
<div>
    <div>
        <div>
            <p>Welcome to Astra Porta.</p>
            <p>Click <a href="https://www.php.cn/link/1b8e84dcae97ad25234484e38615c570">here</a> to login.</p>
        </div>
    </div>
</div>
{{template "footer"}}
登录后复制

以上就是Gin Web 应用程序仅渲染一个模板的详细内容,更多请关注php中文网其它相关文章!

我们今天的关于Go 语言十三Gin Web 框架的分享就到这里,谢谢您的阅读,如果想了解更多关于asp.net-web-api – System.Web.Routing.RouteCollection不包含“MapHttpRoute”的定义 – VS 2012,Web API、asp.net-web-api – 在ASP.NET Web API控制器的nunit测试中实例化新的System.Web.Http.OData.Query.ODataQueryOptions、AutoTLS 和 Gin (gin-gonic) 无法读取 SSL 证书、Gin Web 应用程序仅渲染一个模板的相关信息,可以在本站进行搜索。

本文标签: