2026-05-08 07:27:06 +08:00
|
|
|
|
package service
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
2026-05-09 16:39:20 +08:00
|
|
|
|
"apigo.cc/go/discover"
|
2026-05-08 07:27:06 +08:00
|
|
|
|
"io"
|
|
|
|
|
|
"mime/multipart"
|
|
|
|
|
|
"net"
|
|
|
|
|
|
"net/http"
|
|
|
|
|
|
"net/textproto"
|
|
|
|
|
|
"net/url"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// UploadFile 上传文件结构
|
|
|
|
|
|
type UploadFile struct {
|
|
|
|
|
|
fileHeader *multipart.FileHeader
|
|
|
|
|
|
Filename string
|
|
|
|
|
|
Header textproto.MIMEHeader
|
|
|
|
|
|
Size int64
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Open 打开上传文件
|
|
|
|
|
|
func (f *UploadFile) Open() (multipart.File, error) {
|
|
|
|
|
|
return f.fileHeader.Open()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Content 获取上传文件内容
|
|
|
|
|
|
func (f *UploadFile) Content() ([]byte, error) {
|
|
|
|
|
|
src, err := f.fileHeader.Open()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
defer src.Close()
|
|
|
|
|
|
return io.ReadAll(src)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-05 19:05:21 +08:00
|
|
|
|
// Header 包装 http.Header 以提供 JS 友好的方法
|
|
|
|
|
|
type Header struct {
|
|
|
|
|
|
H http.Header `js:"-"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (h *Header) Get(key string) string {
|
|
|
|
|
|
return h.H.Get(key)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (h *Header) Set(key, value string) {
|
|
|
|
|
|
h.H.Set(key, value)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (h *Header) Add(key, value string) {
|
|
|
|
|
|
h.H.Add(key, value)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (h *Header) Del(key string) {
|
|
|
|
|
|
h.H.Del(key)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (h *Header) Values(key string) []string {
|
|
|
|
|
|
return h.H.Values(key)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-08 07:27:06 +08:00
|
|
|
|
// Request 封装 http.Request
|
|
|
|
|
|
type Request struct {
|
2026-06-05 19:05:21 +08:00
|
|
|
|
*http.Request `js:"-"`
|
|
|
|
|
|
contextValues map[string]any `js:"-"`
|
2026-05-08 07:27:06 +08:00
|
|
|
|
Id string
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-05 19:05:21 +08:00
|
|
|
|
// Cookie 简化的 JS 友好 Cookie 结构
|
|
|
|
|
|
type Cookie struct {
|
|
|
|
|
|
Name string
|
|
|
|
|
|
Value string
|
|
|
|
|
|
Path string
|
|
|
|
|
|
Domain string
|
|
|
|
|
|
MaxAge int
|
|
|
|
|
|
Secure bool
|
|
|
|
|
|
HttpOnly bool
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (r *Request) GetCookie(name string) *Cookie {
|
|
|
|
|
|
c, err := r.Request.Cookie(name)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
return &Cookie{
|
|
|
|
|
|
Name: c.Name,
|
|
|
|
|
|
Value: c.Value,
|
|
|
|
|
|
Path: c.Path,
|
|
|
|
|
|
Domain: c.Domain,
|
|
|
|
|
|
MaxAge: c.MaxAge,
|
|
|
|
|
|
Secure: c.Secure,
|
|
|
|
|
|
HttpOnly: c.HttpOnly,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (r *Request) GetCookies() []*Cookie {
|
|
|
|
|
|
res := make([]*Cookie, 0)
|
|
|
|
|
|
for _, c := range r.Request.Cookies() {
|
|
|
|
|
|
res = append(res, &Cookie{
|
|
|
|
|
|
Name: c.Name,
|
|
|
|
|
|
Value: c.Value,
|
|
|
|
|
|
Path: c.Path,
|
|
|
|
|
|
Domain: c.Domain,
|
|
|
|
|
|
MaxAge: c.MaxAge,
|
|
|
|
|
|
Secure: c.Secure,
|
|
|
|
|
|
HttpOnly: c.HttpOnly,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
return res
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// AddCookie 遮蔽原生的 AddCookie
|
|
|
|
|
|
func (r *Request) AddCookie(c *Cookie) {
|
|
|
|
|
|
if c == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
r.Request.AddCookie(&http.Cookie{
|
|
|
|
|
|
Name: c.Name,
|
|
|
|
|
|
Value: c.Value,
|
|
|
|
|
|
Path: c.Path,
|
|
|
|
|
|
Domain: c.Domain,
|
|
|
|
|
|
MaxAge: c.MaxAge,
|
|
|
|
|
|
Secure: c.Secure,
|
|
|
|
|
|
HttpOnly: c.HttpOnly,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CookiesNamed 遮蔽原生的 CookiesNamed
|
|
|
|
|
|
func (r *Request) CookiesNamed(name string) []*Cookie {
|
|
|
|
|
|
res := make([]*Cookie, 0)
|
|
|
|
|
|
for _, c := range r.Request.Cookies() {
|
|
|
|
|
|
if c.Name == name {
|
|
|
|
|
|
res = append(res, &Cookie{
|
|
|
|
|
|
Name: c.Name,
|
|
|
|
|
|
Value: c.Value,
|
|
|
|
|
|
Path: c.Path,
|
|
|
|
|
|
Domain: c.Domain,
|
|
|
|
|
|
MaxAge: c.MaxAge,
|
|
|
|
|
|
Secure: c.Secure,
|
|
|
|
|
|
HttpOnly: c.HttpOnly,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return res
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (r *Request) Header() *Header {
|
|
|
|
|
|
return &Header{H: r.Request.Header}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-08 07:27:06 +08:00
|
|
|
|
// NewRequest 创建 Request 包装
|
|
|
|
|
|
func NewRequest(httpRequest *http.Request) *Request {
|
|
|
|
|
|
return &Request{
|
|
|
|
|
|
Request: httpRequest,
|
|
|
|
|
|
contextValues: make(map[string]any),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ResetPath 重写请求路径
|
|
|
|
|
|
func (r *Request) ResetPath(path string) {
|
|
|
|
|
|
r.RequestURI = path
|
|
|
|
|
|
if u, err := url.Parse(path); err == nil {
|
|
|
|
|
|
r.URL = u
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Set 设置请求上下文变量
|
|
|
|
|
|
func (r *Request) Set(key string, value any) {
|
|
|
|
|
|
r.contextValues[key] = value
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Get 获取请求上下文变量
|
|
|
|
|
|
func (r *Request) Get(key string) any {
|
|
|
|
|
|
return r.contextValues[key]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// MakeUrl 根据当前请求构建完整 URL
|
|
|
|
|
|
func (r *Request) MakeUrl(path string) string {
|
2026-06-05 19:05:21 +08:00
|
|
|
|
scheme := r.Header().Get(discover.HeaderScheme)
|
2026-05-08 07:27:06 +08:00
|
|
|
|
if scheme == "" {
|
|
|
|
|
|
scheme = "http"
|
|
|
|
|
|
}
|
2026-06-05 19:05:21 +08:00
|
|
|
|
host := r.Header().Get(discover.HeaderHost)
|
2026-05-08 07:27:06 +08:00
|
|
|
|
if host == "" {
|
|
|
|
|
|
host = r.Host
|
|
|
|
|
|
}
|
|
|
|
|
|
return scheme + "://" + host + path
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-09 16:39:20 +08:00
|
|
|
|
// DeviceId 获取设备 ID
|
|
|
|
|
|
func (r *Request) DeviceId() string {
|
2026-06-05 19:05:21 +08:00
|
|
|
|
return r.Header().Get(discover.HeaderDeviceID)
|
2026-05-09 16:39:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SessionId 获取会话 ID
|
|
|
|
|
|
func (r *Request) SessionId() string {
|
2026-06-05 19:05:21 +08:00
|
|
|
|
return r.Header().Get(discover.HeaderSessionID)
|
2026-05-08 07:27:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SetUserId 设置用户 ID(传递给下游)
|
|
|
|
|
|
func (r *Request) SetUserId(userId string) {
|
2026-06-05 19:05:21 +08:00
|
|
|
|
r.Header().Set(discover.HeaderUserID, userId)
|
2026-05-08 07:27:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-09 16:39:20 +08:00
|
|
|
|
// ClientIp 获取真实 IP
|
|
|
|
|
|
func (r *Request) ClientIp() string {
|
2026-06-05 19:05:21 +08:00
|
|
|
|
ip := r.Header().Get(discover.HeaderClientIP)
|
2026-05-08 07:27:06 +08:00
|
|
|
|
if ip == "" {
|
2026-06-05 19:05:21 +08:00
|
|
|
|
ip = r.Header().Get(discover.HeaderForwardedFor)
|
2026-05-08 07:27:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
if ip == "" {
|
|
|
|
|
|
host, _, err := net.SplitHostPort(r.RemoteAddr)
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
return host
|
|
|
|
|
|
}
|
|
|
|
|
|
return r.RemoteAddr
|
|
|
|
|
|
}
|
|
|
|
|
|
return ip
|
|
|
|
|
|
}
|