代码拉取完成,页面将自动刷新
package msgo
import (
"errors"
"gitee.com/MrDaiM/msgo/binding"
msgLog "gitee.com/MrDaiM/msgo/log"
"gitee.com/MrDaiM/msgo/render"
"html/template"
"io"
"log"
"mime/multipart"
"net/http"
"net/url"
"os"
"strings"
"sync"
)
// 2 的 10次方是1024 2^10 * 2^10 = 2^(10+10) = 2^20
const defaultMaxMemory = 32 << 20 //32M
type Context struct {
W http.ResponseWriter
R *http.Request
engine *Engine
StatusCode int
queryCache url.Values // query 参数
formCache url.Values // form 表单参数
DisallowUnknownFields bool // 如果想要实现参数中有的属性,但是对应的结构体没有,报错,也就是检查结构体是否有效
IsValidate bool // 是否校验参数
Logger *msgLog.Logger
Keys map[string]any
mu sync.RWMutex
sameSite http.SameSite // 做安全性的操作
}
func (c *Context) SetSameSite(s http.SameSite) {
c.sameSite = s
}
func (c *Context) Set(key string, value any) {
c.mu.Lock()
defer c.mu.Unlock()
if c.Keys == nil {
c.Keys = make(map[string]any)
}
c.Keys[key] = value
}
func (c *Context) Get(key string) (value any, ok bool) {
c.mu.RLock()
defer c.mu.RUnlock()
value, ok = c.Keys[key]
return
}
func (c *Context) SetBasicAuth(username, password string) {
c.R.Header.Set("Authorization", "Basic "+BasicAuth(username, password))
}
func (c *Context) SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool) {
if path == "" {
path = "/"
}
http.SetCookie(c.W, &http.Cookie{
Name: name,
Value: url.QueryEscape(value),
MaxAge: maxAge,
Domain: domain,
SameSite: c.sameSite,
Secure: secure,
HttpOnly: httpOnly,
})
}
func (c *Context) GetHeader(key string) string {
return c.R.Header.Get(key)
}
func (c *Context) BindJson(obj any) error {
json := binding.JSON
json.DisallowUnknownFields = true
json.IsValidate = true
return c.MustBindWith(obj, json)
}
func (c *Context) BindXML(obj any) error {
return c.MustBindWith(obj, binding.XML)
}
func (c *Context) MustBindWith(obj any, jsonBinding binding.Binding) error {
// 如果发生错误, 返回400状态码 参数错误
if err := c.ShouldBindWith(obj, jsonBinding); err != nil {
c.W.WriteHeader(http.StatusBadRequest)
return err
}
return nil
}
func (c *Context) ShouldBindWith(obj any, b binding.Binding) error {
return b.Bind(c.R, obj)
}
func (c *Context) initPostFormCache() {
if c.R != nil {
// 解析 ParseMultipartForm 支持表单传文件
if err := c.R.ParseMultipartForm(defaultMaxMemory); err != nil {
// 如果此方法不传入文件 或报错,那么这里忽略这个错误
if !errors.Is(err, http.ErrNotMultipart) { // http.ErrNotMultipart 除了这个错误,其他错误输出
log.Println(err)
}
}
c.formCache = c.R.PostForm
} else {
c.formCache = url.Values{}
}
}
func (c *Context) GetPostFrom(key string) (string, bool) {
if values, ok := c.GetPostFormArray(key); ok {
return values[0], ok
}
return "", false
}
func (c *Context) PostFromArray(key string) (values []string) {
values, _ = c.GetPostFormArray(key)
return
}
func (c *Context) GetPostFormArray(key string) ([]string, bool) {
c.initPostFormCache()
values, ok := c.formCache[key]
return values, ok
}
func (c *Context) GetPostFormMap(key string) (map[string]string, bool) {
c.initPostFormCache()
return c.get(c.formCache, key)
}
func (c *Context) PostFormMap(key string) (dicts map[string]string) {
dicts, _ = c.GetPostFormMap(key)
return
}
// FormFile 支持文件
func (c *Context) FormFile(name string) (*multipart.FileHeader, error) {
file, header, err := c.R.FormFile(name)
if err != nil {
log.Println(err)
return nil, err
}
defer file.Close()
return header, nil
}
// FormFiles 支持文件
func (c *Context) FormFiles(name string) []*multipart.FileHeader {
multipartForm, err := c.MultipartForm()
if err != nil {
return make([]*multipart.FileHeader, 0)
}
return multipartForm.File[name]
}
// SaveUploadFile 保存文件
func (c *Context) SaveUploadFile(file *multipart.FileHeader, dst string) error {
src, err := file.Open()
if err != nil {
return err
}
defer src.Close()
out, err := os.Create(dst)
if err != nil {
return err
}
defer out.Close()
_, err = io.Copy(out, src)
return err
}
func (c *Context) MultipartForm() (*multipart.Form, error) {
err := c.R.ParseMultipartForm(defaultMaxMemory)
return c.R.MultipartForm, err
}
func (c *Context) QueryMap(key string) (dicts map[string]string) {
dicts, _ = c.GetQueryMap(key)
return
}
func (c *Context) GetQueryMap(key string) (map[string]string, bool) {
c.initQueryCache()
return c.get(c.queryCache, key)
}
// get 获取 map 类型的参数 形如http://localhost:8080/queryMap?user[id]=1&user[name]=张三
func (c *Context) get(m map[string][]string, key string) (map[string]string, bool) {
// user[id]=1&user[name]=张三
dicts := make(map[string]string)
exist := false
for k, value := range m {
// key === user[id], value === 1
index := strings.IndexByte(k, '[')
log.Println("index:", index)
log.Println("key:", k[0:index])
if i := strings.IndexByte(k, '['); i >= 1 && k[0:i] == key {
if j := strings.IndexByte(k[i+1:], ']'); j >= 1 {
exist = true
// user[id] ==> id
dicts[k[i+1:][:j]] = value[0]
}
}
}
return dicts, exist
}
func (c *Context) DefaultQuery(key, defaultValue string) string {
array, ok := c.GetQueryArray(key)
if !ok {
return defaultValue
}
return array[0]
}
// GetQuery http://xxx.com/user/add?id=1&age=20&username=张三
func (c *Context) GetQuery(key string) string {
c.initQueryCache()
return c.queryCache.Get(key)
}
// QueryArray 一个key 对应多个value http://127.0.0.1:8111/user/add?id=100&id=102
func (c *Context) QueryArray(key string) (values []string) {
c.initQueryCache()
values, _ = c.queryCache[key]
return
}
func (c *Context) GetQueryArray(key string) (values []string, ok bool) {
c.initQueryCache()
values, ok = c.queryCache[key]
return
}
func (c *Context) initQueryCache() {
//if c.queryCache == nil {
// if c.R != nil {
// c.queryCache = c.R.URL.Query()
// } else {
// c.queryCache = url.Values{}
// }
//}
if c.R != nil {
c.queryCache = c.R.URL.Query()
} else {
c.queryCache = url.Values{}
}
}
func (c *Context) HTML(status int, html string) error {
//状态是200 默认不设置的话 如果调用了 write这个方法 实际上默认返回状态 200
return c.Render(status, &render.HTML{Data: html, IsTemplate: false})
}
func (c *Context) Template(name string, data any) error {
c.W.Header().Set("Content-Type", "text/html; charset=utf-8")
err := c.engine.HTMLRender.Template.ExecuteTemplate(c.W, name, data)
return err
}
func (c *Context) HTMLTemplate(name string, funcMap template.FuncMap, data any, fileName ...string) error {
c.W.Header().Set("Content-Type", "text/html; charset=utf-8")
t := template.New(name)
t.Funcs(funcMap)
t, err := t.ParseFiles(fileName...) // 具体的某个文件
if err != nil {
log.Println(err)
return err
}
err = t.Execute(c.W, data)
if err != nil {
log.Println(err)
}
return err
}
func (c *Context) HTMLTemplateGlob(name string, data any, pattern string) error {
//状态是200 默认不设置的话 如果调用了 write这个方法 实际上默认返回状态 200
c.W.Header().Set("Content-Type", "text/html; charset=utf-8")
t := template.New(name)
t, err := t.ParseGlob(pattern) // 支持泛型 通配符
if err != nil {
return err
}
err = t.Execute(c.W, data)
return err
}
func (c *Context) JSON(status int, data any) error {
//状态是200 默认不设置的话 如果调用了 write这个方法 实际上默认返回状态 200
return c.Render(status, &render.JSON{Data: data})
}
func (c *Context) XML(status int, data any) error {
return c.Render(status, &render.XML{
Data: data,
})
}
// File 下载文件,默认
func (c *Context) File(filePath string) {
http.ServeFile(c.W, c.R, filePath) // 下载文件
}
// FileAttachment 下载文件,自定义文件名
func (c *Context) FileAttachment(filePath, filename string) {
if isASCII(filename) {
c.W.Header().Set("Content-Disposition", `attachment; filename="`+filename+`"`)
} else {
c.W.Header().Set("Content-Disposition", `attachment; filename*=UTF-8''`+url.QueryEscape(filename))
}
http.ServeFile(c.W, c.R, filePath)
}
// FileFromFS -m filepath 是相对文件系统的路径
func (c *Context) FileFromFS(filepath string, fs http.FileSystem) {
defer func(old string) {
c.R.URL.Path = old
}(c.R.URL.Path)
c.R.URL.Path = filepath
http.FileServer(fs).ServeHTTP(c.W, c.R)
}
func (c *Context) Redirect(status int, url string) error {
return c.Render(status, &render.Redirect{
Code: status,
Request: c.R,
Location: url,
})
}
func (c *Context) String(status int, format string, values ...any) (err error) {
err = c.Render(status, &render.String{
Format: format,
Data: values,
})
return
}
func (c *Context) Render(statusCode int, r render.Render) error {
// 先设置
//c.W.WriteHeader(statusCode)
//如果设置了statusCode,对header的修改就不生效了
err := r.Render(c.W, statusCode)
c.StatusCode = statusCode
//多次调用 WriteHeader 就会产生这样的警告 superfluous response.WriteHeader
// 错误信息 http: superfluous response.WriteHeader call from gitee.com/MrDaiM/msgo.(*Context).Render (context.go:318)
return err
}
func (c *Context) Fail(code int, msg string) {
_ = c.String(code, msg)
}
func (c *Context) HandleWithError(statusCode int, obj any, err error) {
if err != nil {
code, data := c.engine.errorHandler(err)
_ = c.JSON(code, data)
return
}
_ = c.JSON(statusCode, obj)
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。