Gin 框架学习:从 reader 读取数据

fromreader.go:

package main

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

func main() {
	router := gin.Default()

	router.GET("/someDataFromReader", func(c *gin.Context) {
		response, err := http.Get("https://www.yangdx.com/res/img/avatar.jpg")
		if err != nil || response.StatusCode != http.StatusOK {
			c.Status(http.StatusServiceUnavailable)
			return
		}

		reader := response.Body
		contentLength := response.ContentLength
		contentType := response.Header.Get("Content-Type")

		extraHeaders := map[string]string{
			"Content-Disposition": `attachment; filename="gopher.jpg"`,
		}

		c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders)
	})

	router.Run(":8080")
}

使用浏览器访问 http://localhost:8080/someDataFromReader 将弹出文件的保持对话框。

分类至 GO
0条评论

Gin 框架学习:多文件上传

upload2.go:

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
	"path/filepath"
)

func main() {
	router := gin.Default()
	// 为 multipart forms 设置较低的内存限制 (默认是 32 MiB)
	// router.MaxMultipartMemory = 8 << 20 // 8 MiB
	router.POST("/upload", func(c *gin.Context) {
		form, _ := c.MultipartForm()
		files := form.File["upload[]"]

		for _, file := range files {
			log.Println(file.Filename)

			dst := "./upload/" + filepath.Base(file.Filename)
			c.SaveUploadedFile(file, dst)
		}

		c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
	})
	router.Run(":8080")
}

使用 curl 测试上传:

$ curl -X POST http://localhost:8080/upload \
    -F "upload[]=@/Users/appleboy/test1.zip" \
    -F "upload[]=@/Users/appleboy/test2.zip" \
    -H "Content-Type: multipart/form-data"

 

分类至 GO
0条评论

Gin 框架学习:单文件上传

upload1.go:

package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"net/http"
	"path/filepath"
)

func main() {
	router := gin.Default()
	// 为 multipart forms 设置较低的内存限制 (默认是 32 MiB)
	// router.MaxMultipartMemory = 8 << 20  // 8 MiB
	router.POST("/upload", func(c *gin.Context) {
		file, err := c.FormFile("file")
		if err != nil {
			c.String(http.StatusBadRequest, fmt.Sprintf("get form err: %s", err.Error()))
		}

		log.Println(file.Filename)

		dst := "./upload/" + filepath.Base(file.Filename)
		if err := c.SaveUploadedFile(file, dst); err != nil {
			c.String(http.StatusBadRequest, fmt.Sprintf("upload file err: %s", err.Error()))
		}

		c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!", file.Filename))
	})

	router.Run(":8080")
}

使用 curl 测试上传:

$ curl -X POST http://localhost:8080/upload \
    -F "file=@/f/folder/test.zip" \
    -H "Content-Type: multipart/form-data"

 

分类至 GO
0条评论

Gin 框架学习:XML/JSON/YAML/ProtoBuf 渲染

xml_json_yaml_protobuf.go:

package main

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

func main() {
	r := gin.Default()

	// gin.H 是 map[string]interface{} 的一种快捷方式
	r.GET("/someJSON", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
	})

	r.GET("/moreJSON", func(c *gin.Context) {
		// 你也可以使用一个结构体
		var msg struct {
			Name    string `json:"user"`
			Message string
			Number  int
		}
		msg.Name = "Lena"
		msg.Message = "hey"
		msg.Number = 123
		// 注意 msg.Name 在 JSON 中变成了 "user"
		// 将输出:{"user":"Lena","Message":"hey","Number":123}
		c.JSON(http.StatusOK, msg)
	})

	r.GET("/someXML", func(c *gin.Context) {
		c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
	})

	r.GET("/someYAML", func(c *gin.Context) {
		c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
	})

	r.GET("/someProtoBuf", func(c *gin.Context) {
		reps := []int64{int64(1), int64(2)}
		label := "test"
		// protobuf 的具体定义写在 testdata/protoexample 文件中。
		data := &protoexample.Test{
			Label: &label,
			Reps:  reps,
		}
		// 请注意,数据在响应中变为二进制数据
		// 将输出被 protoexample.Test protobuf 序列化了的数据
		c.ProtoBuf(http.StatusOK, data)
	})

	// 监听并在 0.0.0.0:8080 上启动服务
	r.Run(":8080")
}

 

分类至 GO
0条评论

Gin 框架学习:SecureJSON

使用 SecureJSON 防止 json 劫持。如果给定的结构是数组值,则默认预置 while(1); 到响应体。

secruejson.go:

package main

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

func main() {
	r := gin.Default()

	r.GET("/someJSON", func(c *gin.Context) {
		names := []string{"lena", "austin", "foo"}

		c.SecureJSON(200, names)
	})

	r.Run(":8080")
}

相关阅读:Why does Google prepend while(1); to their JSON responses?

分类至 GO
0条评论

Gin 框架学习:Query 和 post form

同时接收 post 参数和 query 参数。

query_post.go:

package main

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

func main() {
	router := gin.Default()

	router.POST("/post", func(c *gin.Context) {
		id := c.Query("id")
		page := c.DefaultQuery("page", "0")
		name := c.PostForm("name")
		message := c.PostForm("message")

		c.String(http.StatusOK, fmt.Sprintf("id: %s; page %s; name: %s; message: %s", id, page, name, message))
	})

	router.Run(":8080")
}

测试:

$ curl -d "name=manu&message=this_is_great" "http://localhost:8080/post?id=1234&page=1"

输出:

id: 1234; page 1; name: manu; message: this_is_great

 

分类至 GO
0条评论

Gin 框架学习:PureJSON

通常,JSON 使用 unicode 替换特殊 HTML 字符,例如 < 变为 \ u003c。如果要按字面对这些字符进行编码,则可以使用 PureJSON。Go 1.6 及更低版本无法使用此功能。

purejson.go:

package main

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

func main() {
	router := gin.Default()

	// 提供 unicode 实体
	router.GET("/json", func(c *gin.Context) {
		// 输出:{"html":"\u003cb\u003eHello, world!\u003c/b\u003e"}
		c.JSON(200, gin.H{
			"html": "<b>Hello, world!</b>",
		})
	})

	// 提供字面字符
	router.GET("/purejson", func(c *gin.Context) {
		// 输出:{"html":"<b>Hello, world!</b>"}
		c.PureJSON(200, gin.H{
			"html": "<b>Hello, world!</b>",
		})
	})

	router.Run(":8080")
}

 

分类至 GO
0条评论

Gin 框架学习:Multipart/Urlencoded 表单

multipart2.go:

package main

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

func main() {
	router := gin.Default()
	router.POST("/form_post", func(c *gin.Context) {
		message := c.PostForm("message")
		nick := c.DefaultPostForm("nick", "anonymous")

		c.JSON(200, gin.H{
			"status":  "posted",
			"message": message,
			"nick":    nick,
		})
	})
	router.Run(":8080")
}

使用 c.PostForm 方法可以直接获取表单字段,而不必事先声明结构体。如果不存在这个字段,则返回空字符串。

使用 c.DefaultPostForm 方法获取表单字段时,如果字段不存在,将返回给定的默认值。这里要注意,只有表单不包括这个字段时才会返回默认值;如果字段为空字符串,返回的就是空字符串而不是默认值。

分类至 GO
0条评论

Gin 框架学习:Multipart/Urlencoded 绑定

multipart1.go:

package main

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

type LoginForm struct {
	User     string `form:"user" binding:"required"`
	Password string `form:"password" binding:"required"`
}

func main() {
	router := gin.Default()
	router.POST("/login", func(c *gin.Context) {
		// 你可以使用显式绑定声明绑定 multipart form:
		// c.ShouldBindWith(&form, binding.Form)
		// 或者简单地使用 ShouldBind 方法自动绑定:
		var form LoginForm
		// 在这种情况下,将自动选择合适的绑定
		if c.ShouldBind(&form) == nil {
			if form.User == "user" && form.Password == "password" {
				c.JSON(200, gin.H{"status": "you are logged in"})
			} else {
				c.JSON(401, gin.H{"status": "unauthorized"})
			}
		}
	})
	router.Run(":8080")
}

 

分类至 GO
0条评论

Gin 框架学习:JSONP

使用 JSONP 向不同域的服务器请求数据。如果查询参数存在回调,则将回调添加到响应体中。

jsonp.go:

package main

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

func main() {
	r := gin.Default()

	r.GET("/JSONP", func(c *gin.Context) {
		data := map[string]interface{}{
			"foo": "bar",
		}

		c.JSONP(200, data)
	})

	r.Run(":8080")
}

运行后访问 http://127.0.0.1:8080/JSONP?callback=myfunc

输出如下:

myfunc({"foo":"bar"});

 

分类至 GO
0条评论