feat(router): 为exports路由添加免认证下载接口
添加exportsDownloadHandler处理函数用于免认证下载文件,并修改路由配置使/download路径跳过认证中间件。当文件URI获取失败时,自动尝试从本地storage目录查找匹配文件。
This commit is contained in:
parent
d0f65da375
commit
20deec5879
|
|
@ -1961,3 +1961,60 @@ func parseIntVal(s string) int {
|
|||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// exportsDownloadHandler 独立的下载处理函数(不需要认证)
|
||||
func exportsDownloadHandler(metaDB, marketingDB, ymtDB *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// 提取 ID,路径格式:/api/exports/{id}/download
|
||||
path := r.URL.Path
|
||||
if !strings.HasPrefix(path, "/api/exports/") || !strings.HasSuffix(path, "/download") {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte("invalid path"))
|
||||
return
|
||||
}
|
||||
|
||||
// 移除 /api/exports/ 和 /download
|
||||
path = strings.TrimPrefix(path, "/api/exports/")
|
||||
path = strings.TrimSuffix(path, "/download")
|
||||
id := strings.TrimSpace(path)
|
||||
|
||||
if id == "" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Write([]byte("missing id"))
|
||||
return
|
||||
}
|
||||
|
||||
rrepo := repo.NewExportRepo()
|
||||
uri, err := rrepo.GetLatestFileURI(metaDB, id)
|
||||
if err != nil {
|
||||
// fallback: try to serve local storage file by job id
|
||||
// search for files named export_job_<id>_*.zip/xlsx/csv
|
||||
dir := "storage"
|
||||
entries, e := os.ReadDir(dir)
|
||||
if e == nil {
|
||||
best := ""
|
||||
var bestInfo os.FileInfo
|
||||
for _, ent := range entries {
|
||||
name := ent.Name()
|
||||
if strings.HasPrefix(name, "export_job_"+id+"_") && (strings.HasSuffix(name, ".zip") || strings.HasSuffix(name, ".xlsx") || strings.HasSuffix(name, ".csv")) {
|
||||
info, _ := os.Stat(filepath.Join(dir, name))
|
||||
if info != nil {
|
||||
if best == "" || info.ModTime().After(bestInfo.ModTime()) {
|
||||
best = name
|
||||
bestInfo = info
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if best != "" {
|
||||
http.ServeFile(w, r, filepath.Join(dir, best))
|
||||
return
|
||||
}
|
||||
}
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
w.Write([]byte("not found"))
|
||||
return
|
||||
}
|
||||
http.ServeFile(w, r, uri)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"database/sql"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func NewRouter(metaDB *sql.DB, marketingDB *sql.DB, marketingAuthDB *sql.DB, resellerDB *sql.DB, ymtDB *sql.DB, grpcAddr string, marketingAPIDomain string) http.Handler {
|
||||
|
|
@ -16,7 +17,19 @@ func NewRouter(metaDB *sql.DB, marketingDB *sql.DB, marketingAuthDB *sql.DB, res
|
|||
mux.Handle("/api/templates", withAccess(withTrace(authMiddleware(TemplatesHandler(metaDB, marketingDB)))))
|
||||
mux.Handle("/api/templates/", withAccess(withTrace(authMiddleware(TemplatesHandler(metaDB, marketingDB)))))
|
||||
mux.Handle("/api/exports", withAccess(withTrace(authMiddleware(ExportsHandler(metaDB, marketingDB, ymtDB)))))
|
||||
mux.Handle("/api/exports/", withAccess(withTrace(authMiddleware(ExportsHandler(metaDB, marketingDB, ymtDB)))))
|
||||
|
||||
// exports 路由处理(特殊处理下载接口)
|
||||
mux.HandleFunc("/api/exports/", func(w http.ResponseWriter, r *http.Request) {
|
||||
path := r.URL.Path
|
||||
// 如果是下载接口,不需要认证
|
||||
if strings.HasSuffix(path, "/download") {
|
||||
exportsDownloadHandler(metaDB, marketingDB, ymtDB).ServeHTTP(w, r)
|
||||
} else {
|
||||
// 其他 exports 路由需要认证
|
||||
withAccess(withTrace(authMiddleware(ExportsHandler(metaDB, marketingDB, ymtDB)))).ServeHTTP(w, r)
|
||||
}
|
||||
})
|
||||
|
||||
mux.Handle("/api/metadata/fields", withAccess(withTrace(authMiddleware(MetadataHandler(metaDB, marketingDB, ymtDB)))))
|
||||
mux.Handle("/api/fields", withAccess(withTrace(authMiddleware(FieldsHandler(marketingDB, ymtDB)))))
|
||||
mux.Handle("/api/fields/", withAccess(withTrace(authMiddleware(FieldsHandler(marketingDB, ymtDB)))))
|
||||
|
|
|
|||
Loading…
Reference in New Issue