mirror of
https://github.com/infinite-iroha/touka.git
synced 2026-02-03 08:51:11 +08:00
Compare commits
3 commits
6c96e189d3
...
87fc425dc4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87fc425dc4 | ||
|
|
76d07364ae | ||
|
|
9ec1d1f2c6 |
4 changed files with 71 additions and 1 deletions
53
context.go
53
context.go
|
|
@ -9,10 +9,13 @@ import (
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
|
"mime"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -649,6 +652,56 @@ func (c *Context) GetRequestURIPath() string {
|
||||||
return c.Request.URL.Path
|
return c.Request.URL.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === 文件操作 ===
|
||||||
|
|
||||||
|
// 将文件内容作为响应body
|
||||||
|
func (c *Context) SetRespBodyFile(code int, filePath string) {
|
||||||
|
// 清理path
|
||||||
|
cleanPath := path.Clean(filePath)
|
||||||
|
|
||||||
|
// 打开文件
|
||||||
|
file, err := os.Open(cleanPath)
|
||||||
|
if err != nil {
|
||||||
|
c.AddError(fmt.Errorf("failed to open file %s: %w", cleanPath, err))
|
||||||
|
c.ErrorUseHandle(http.StatusInternalServerError, fmt.Errorf("failed to open file: %w", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// 获取文件信息以获取文件大小和MIME类型
|
||||||
|
fileInfo, err := file.Stat()
|
||||||
|
if err != nil {
|
||||||
|
c.AddError(fmt.Errorf("failed to get file info for %s: %w", cleanPath, err))
|
||||||
|
c.ErrorUseHandle(http.StatusInternalServerError, fmt.Errorf("failed to get file info: %w", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试根据文件扩展名猜测 Content-Type
|
||||||
|
contentType := mime.TypeByExtension(path.Ext(cleanPath))
|
||||||
|
if contentType == "" {
|
||||||
|
// 如果无法猜测,则使用默认的二进制流类型
|
||||||
|
contentType = "application/octet-stream"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置响应头
|
||||||
|
c.Writer.Header().Set("Content-Type", contentType)
|
||||||
|
c.Writer.Header().Set("Content-Length", fmt.Sprintf("%d", fileInfo.Size()))
|
||||||
|
// 还可以设置 Content-Disposition 来控制浏览器是下载还是直接显示
|
||||||
|
// c.Writer.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, path.Base(cleanPath)))
|
||||||
|
|
||||||
|
// 设置状态码
|
||||||
|
c.Writer.WriteHeader(code)
|
||||||
|
|
||||||
|
// 将文件内容写入响应体
|
||||||
|
_, err = copyb.Copy(c.Writer, file)
|
||||||
|
if err != nil {
|
||||||
|
c.AddError(fmt.Errorf("failed to write file %s to response: %w", cleanPath, err))
|
||||||
|
// 注意:这里可能无法设置错误状态码,因为头部可能已经发送
|
||||||
|
// 可以在调用 SetRespBodyFile 之前检查错误,或者在中间件中处理 Context.Errors
|
||||||
|
}
|
||||||
|
c.Abort() // 文件发送后中止后续处理
|
||||||
|
}
|
||||||
|
|
||||||
// == cookie ===
|
// == cookie ===
|
||||||
|
|
||||||
// SetSameSite 设置响应的 SameSite cookie 属性
|
// SetSameSite 设置响应的 SameSite cookie 属性
|
||||||
|
|
|
||||||
15
engine.go
15
engine.go
|
|
@ -121,6 +121,21 @@ func defaultErrorWarp(handler ErrorHandler) ErrorHandler {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 查看context内有没有收集到error
|
||||||
|
if len(c.Errors) > 0 {
|
||||||
|
c.Errorf("errpage: context errors: %v, current error: %v", errors.Join(c.Errors...), err)
|
||||||
|
if err == nil {
|
||||||
|
err = errors.Join(c.Errors...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 如果客户端已经断开连接,则不尝试写入响应
|
||||||
|
// 避免在客户端已关闭连接后写入响应导致的问题
|
||||||
|
// 检查 context.Context 是否已取消
|
||||||
|
if errors.Is(c.Request.Context().Err(), context.Canceled) {
|
||||||
|
log.Printf("errpage: client disconnected, skipping error page rendering for status %d, err: %v", code, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
handler(c, code, err)
|
handler(c, code, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
go.mod
2
go.mod
|
|
@ -4,7 +4,7 @@ go 1.24.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/WJQSERVER-STUDIO/go-utils/copyb v0.0.4
|
github.com/WJQSERVER-STUDIO/go-utils/copyb v0.0.4
|
||||||
github.com/WJQSERVER-STUDIO/httpc v0.7.0
|
github.com/WJQSERVER-STUDIO/httpc v0.7.1
|
||||||
github.com/fenthope/reco v0.0.3
|
github.com/fenthope/reco v0.0.3
|
||||||
github.com/go-json-experiment/json v0.0.0-20250517221953-25912455fbc8
|
github.com/go-json-experiment/json v0.0.0-20250517221953-25912455fbc8
|
||||||
)
|
)
|
||||||
|
|
|
||||||
2
go.sum
2
go.sum
|
|
@ -2,6 +2,8 @@ github.com/WJQSERVER-STUDIO/go-utils/copyb v0.0.4 h1:JLtFd00AdFg/TP+dtvIzLkdHwKU
|
||||||
github.com/WJQSERVER-STUDIO/go-utils/copyb v0.0.4/go.mod h1:FZ6XE+4TKy4MOfX1xWKe6Rwsg0ucYFCdNh1KLvyKTfc=
|
github.com/WJQSERVER-STUDIO/go-utils/copyb v0.0.4/go.mod h1:FZ6XE+4TKy4MOfX1xWKe6Rwsg0ucYFCdNh1KLvyKTfc=
|
||||||
github.com/WJQSERVER-STUDIO/httpc v0.7.0 h1:iHhqlxppJBjlmvsIjvLZKRbWXqSdbeSGGofjHGmqGJc=
|
github.com/WJQSERVER-STUDIO/httpc v0.7.0 h1:iHhqlxppJBjlmvsIjvLZKRbWXqSdbeSGGofjHGmqGJc=
|
||||||
github.com/WJQSERVER-STUDIO/httpc v0.7.0/go.mod h1:M7KNUZjjhCkzzcg9lBPs9YfkImI+7vqjAyjdA19+joE=
|
github.com/WJQSERVER-STUDIO/httpc v0.7.0/go.mod h1:M7KNUZjjhCkzzcg9lBPs9YfkImI+7vqjAyjdA19+joE=
|
||||||
|
github.com/WJQSERVER-STUDIO/httpc v0.7.1 h1:D3NlfY52pwKIOSzkdRrLinUynyKELrcPZEO8QjlBq2M=
|
||||||
|
github.com/WJQSERVER-STUDIO/httpc v0.7.1/go.mod h1:M7KNUZjjhCkzzcg9lBPs9YfkImI+7vqjAyjdA19+joE=
|
||||||
github.com/fenthope/reco v0.0.3 h1:RmnQ0D9a8PWtwOODawitTe4BztTnS9wYwrDbipISNq4=
|
github.com/fenthope/reco v0.0.3 h1:RmnQ0D9a8PWtwOODawitTe4BztTnS9wYwrDbipISNq4=
|
||||||
github.com/fenthope/reco v0.0.3/go.mod h1:mDkGLHte5udWTIcjQTxrABRcf56SSdxBOCLgrRDwI/Y=
|
github.com/fenthope/reco v0.0.3/go.mod h1:mDkGLHte5udWTIcjQTxrABRcf56SSdxBOCLgrRDwI/Y=
|
||||||
github.com/go-json-experiment/json v0.0.0-20250517221953-25912455fbc8 h1:o8UqXPI6SVwQt04RGsqKp3qqmbOfTNMqDrWsc4O47kk=
|
github.com/go-json-experiment/json v0.0.0-20250517221953-25912455fbc8 h1:o8UqXPI6SVwQt04RGsqKp3qqmbOfTNMqDrWsc4O47kk=
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue