From b80cb0c2d83ad3cba6fd1567fd40303b261a969c Mon Sep 17 00:00:00 2001 From: keven Date: Sat, 18 Oct 2025 23:54:11 +0800 Subject: [PATCH 1/5] refactor(backend,worker): update environment variable keys for consistency and improve configuration handling across backend and worker modules --- backend/internal/controllers/download.go | 4 ++-- backend/internal/controllers/file.go | 2 +- backend/internal/controllers/stat.go | 2 +- backend/internal/utils/asyncq.go | 6 +++--- backend/internal/utils/env.go | 10 +++++++--- backend/internal/utils/password.go | 2 +- backend/internal/utils/password_test.go | 12 ++++++------ backend/internal/utils/redis.go | 2 +- worker/internal/utils/asyncq.go | 2 +- worker/internal/utils/env.go | 10 +++++++--- worker/internal/utils/redis.go | 2 +- worker/main.go | 4 ++-- 12 files changed, 33 insertions(+), 25 deletions(-) diff --git a/backend/internal/controllers/download.go b/backend/internal/controllers/download.go index e337626..5fefea6 100644 --- a/backend/internal/controllers/download.go +++ b/backend/internal/controllers/download.go @@ -25,7 +25,7 @@ func DownloadShare(c echo.Context) error { } claims := DownloadShareClaims{} t, err := jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) { - return []byte(utils.GetEnv("download_secret")), nil + return []byte(utils.GetEnv("download.secret")), nil }) if err != nil { return utils.HTTPErrorHandler(c, err) @@ -96,7 +96,7 @@ func VaildateShare(c echo.Context) error { }) // Sign and get the complete encoded token as a string using the secret - downloadToken, err := token.SignedString([]byte(utils.GetEnv("download_secret"))) + downloadToken, err := token.SignedString([]byte(utils.GetEnv("download.secret"))) if err != nil { return utils.HTTPErrorHandler(c, err) } diff --git a/backend/internal/controllers/file.go b/backend/internal/controllers/file.go index c7511da..16cd3b9 100644 --- a/backend/internal/controllers/file.go +++ b/backend/internal/controllers/file.go @@ -40,7 +40,7 @@ func CreateUploadTask(c echo.Context) error { "chunk_size": fileInfo.ChunkSize, }) } - maxStorageSize, err := utils.GetFileSize(utils.GetEnv("MAX_LOCALSTORAGE_SIZE")) + maxStorageSize, err := utils.GetFileSize(utils.GetEnv("upload.maximum")) if err != nil { return utils.HTTPErrorHandler(c, err) } diff --git a/backend/internal/controllers/stat.go b/backend/internal/controllers/stat.go index 234cfb2..50d53df 100644 --- a/backend/internal/controllers/stat.go +++ b/backend/internal/controllers/stat.go @@ -70,7 +70,7 @@ func GetStat(c echo.Context) error { return utils.HTTPErrorHandler(c, err) } - maxStorageSize, err := utils.GetFileSize(utils.GetEnv("MAX_LOCALSTORAGE_SIZE")) + maxStorageSize, err := utils.GetFileSize(utils.GetEnv("upload.maximum")) if err != nil { return utils.HTTPErrorHandler(c, err) } diff --git a/backend/internal/utils/asyncq.go b/backend/internal/utils/asyncq.go index 74955e9..ae5fea0 100644 --- a/backend/internal/utils/asyncq.go +++ b/backend/internal/utils/asyncq.go @@ -3,17 +3,17 @@ package utils import "github.com/hibiken/asynq" func GetQueueClient() *asynq.Client { - opt := RedisURI2AsynqOpt(GetEnv("REDIS_URL")) + opt := RedisURI2AsynqOpt(GetEnv("redis.url")) return asynq.NewClient(opt) } func GetQueueInspector() *asynq.Inspector { - opt := RedisURI2AsynqOpt(GetEnv("REDIS_URL")) + opt := RedisURI2AsynqOpt(GetEnv("redis.url")) return asynq.NewInspector(opt) } func RedisURI2AsynqOpt(uri string) asynq.RedisConnOpt { - opt, err := asynq.ParseRedisURI(GetEnv("REDIS_URL")) + opt, err := asynq.ParseRedisURI(GetEnv("redis.url")) if err != nil { panic(err) } diff --git a/backend/internal/utils/env.go b/backend/internal/utils/env.go index b8d0208..c13b89f 100644 --- a/backend/internal/utils/env.go +++ b/backend/internal/utils/env.go @@ -1,6 +1,8 @@ package utils import ( + "strings" + "github.com/spf13/viper" ) @@ -15,12 +17,14 @@ func InitEnv() { return } v = viper.New() - v.SetConfigName(".env") - v.SetConfigType("env") + v.SetConfigName("config.yaml") + v.SetConfigType("yaml") + v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) v.AddConfigPath(".") v.AddConfigPath("../") v.AutomaticEnv() - if err := v.ReadInConfig(); err != nil { + err := v.ReadInConfig() + if err != nil { if _, ok := err.(viper.ConfigFileNotFoundError); !ok { // 只有当错误不是"配置文件未找到"时才 panic panic(err) diff --git a/backend/internal/utils/password.go b/backend/internal/utils/password.go index 9909f77..2243af7 100644 --- a/backend/internal/utils/password.go +++ b/backend/internal/utils/password.go @@ -8,7 +8,7 @@ import ( ) func GeneratePasswordHash(password string) (string, error) { - salt := GetEnv("PASSWORD_SALT") + salt := GetEnv("password.salt") if salt == "" { return "", errors.New("请配置PASSWORD_SALT") } diff --git a/backend/internal/utils/password_test.go b/backend/internal/utils/password_test.go index 42d160e..000b1a6 100644 --- a/backend/internal/utils/password_test.go +++ b/backend/internal/utils/password_test.go @@ -9,8 +9,8 @@ import ( func TestGeneratePasswordHash(t *testing.T) { // 保存原始环境变量 - originalSalt := os.Getenv("PASSWORD_SALT") - defer os.Setenv("PASSWORD_SALT", originalSalt) + originalSalt := os.Getenv("password.salt") + defer os.Setenv("password.salt", originalSalt) tests := []struct { name string @@ -20,11 +20,11 @@ func TestGeneratePasswordHash(t *testing.T) { errorMsg string }{ { - name: "PASSWORD_SALT未配置", + name: "password.salt未配置", password: "testpassword", salt: "", expectError: true, - errorMsg: "请配置PASSWORD_SALT", + errorMsg: "请配置password.salt", }, { name: "正常生成哈希", @@ -38,9 +38,9 @@ func TestGeneratePasswordHash(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // 设置环境变量 if tt.salt != "" { - os.Setenv("PASSWORD_SALT", tt.salt) + os.Setenv("password.salt", tt.salt) } else { - os.Unsetenv("PASSWORD_SALT") + os.Unsetenv("password.salt") } hash, err := GeneratePasswordHash(tt.password) diff --git a/backend/internal/utils/redis.go b/backend/internal/utils/redis.go index f770d76..1f8f38c 100644 --- a/backend/internal/utils/redis.go +++ b/backend/internal/utils/redis.go @@ -10,7 +10,7 @@ var rdb *redis.Client = InitRedis() var ctx = context.Background() func InitRedis() *redis.Client { - opt, err := redis.ParseURL(GetEnv("REDIS_URL")) + opt, err := redis.ParseURL(GetEnv("redis.url")) if err != nil { panic(err) } diff --git a/worker/internal/utils/asyncq.go b/worker/internal/utils/asyncq.go index 9ed612f..a5b653e 100644 --- a/worker/internal/utils/asyncq.go +++ b/worker/internal/utils/asyncq.go @@ -3,7 +3,7 @@ package utils import "github.com/hibiken/asynq" func RedisURI2AsynqOpt(uri string) asynq.RedisConnOpt { - opt, err := asynq.ParseRedisURI(GetEnv("REDIS_URL")) + opt, err := asynq.ParseRedisURI(GetEnv("redis.url")) if err != nil { panic(err) } diff --git a/worker/internal/utils/env.go b/worker/internal/utils/env.go index b8d0208..c13b89f 100644 --- a/worker/internal/utils/env.go +++ b/worker/internal/utils/env.go @@ -1,6 +1,8 @@ package utils import ( + "strings" + "github.com/spf13/viper" ) @@ -15,12 +17,14 @@ func InitEnv() { return } v = viper.New() - v.SetConfigName(".env") - v.SetConfigType("env") + v.SetConfigName("config.yaml") + v.SetConfigType("yaml") + v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) v.AddConfigPath(".") v.AddConfigPath("../") v.AutomaticEnv() - if err := v.ReadInConfig(); err != nil { + err := v.ReadInConfig() + if err != nil { if _, ok := err.(viper.ConfigFileNotFoundError); !ok { // 只有当错误不是"配置文件未找到"时才 panic panic(err) diff --git a/worker/internal/utils/redis.go b/worker/internal/utils/redis.go index f770d76..1f8f38c 100644 --- a/worker/internal/utils/redis.go +++ b/worker/internal/utils/redis.go @@ -10,7 +10,7 @@ var rdb *redis.Client = InitRedis() var ctx = context.Background() func InitRedis() *redis.Client { - opt, err := redis.ParseURL(GetEnv("REDIS_URL")) + opt, err := redis.ParseURL(GetEnv("redis.url")) if err != nil { panic(err) } diff --git a/worker/main.go b/worker/main.go index 0c9c279..915c541 100644 --- a/worker/main.go +++ b/worker/main.go @@ -23,8 +23,8 @@ func main() { zap.ReplaceGlobals(logger) srv := asynq.NewServer( - utils.RedisURI2AsynqOpt(utils.GetEnv("REDIS_URL")), - asynq.Config{Concurrency: cast.ToInt(utils.GetEnvWithDefault("WORKER_CONCURRENCY", "4"))}, + utils.RedisURI2AsynqOpt(utils.GetEnv("redis.url")), + asynq.Config{Concurrency: cast.ToInt(utils.GetEnvWithDefault("worker.concurrency", "4"))}, ) mux := asynq.NewServeMux() From 12efc10e0e396b2e5501624650c440b9a2530aaa Mon Sep 17 00:00:00 2001 From: keven Date: Sun, 19 Oct 2025 00:05:56 +0800 Subject: [PATCH 2/5] refactor(backend): standardize environment variable names for download and password handling, enhancing consistency and clarity --- backend/internal/controllers/download.go | 4 ++-- backend/internal/utils/password.go | 2 +- backend/internal/utils/password_test.go | 12 ++++++------ backend/main.go | 5 +++-- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/backend/internal/controllers/download.go b/backend/internal/controllers/download.go index 5fefea6..6ee498f 100644 --- a/backend/internal/controllers/download.go +++ b/backend/internal/controllers/download.go @@ -25,7 +25,7 @@ func DownloadShare(c echo.Context) error { } claims := DownloadShareClaims{} t, err := jwt.ParseWithClaims(token, &claims, func(token *jwt.Token) (interface{}, error) { - return []byte(utils.GetEnv("download.secret")), nil + return []byte(utils.GetEnv("share.download_secret")), nil }) if err != nil { return utils.HTTPErrorHandler(c, err) @@ -96,7 +96,7 @@ func VaildateShare(c echo.Context) error { }) // Sign and get the complete encoded token as a string using the secret - downloadToken, err := token.SignedString([]byte(utils.GetEnv("download.secret"))) + downloadToken, err := token.SignedString([]byte(utils.GetEnv("share.download_secret"))) if err != nil { return utils.HTTPErrorHandler(c, err) } diff --git a/backend/internal/utils/password.go b/backend/internal/utils/password.go index 2243af7..a503022 100644 --- a/backend/internal/utils/password.go +++ b/backend/internal/utils/password.go @@ -8,7 +8,7 @@ import ( ) func GeneratePasswordHash(password string) (string, error) { - salt := GetEnv("password.salt") + salt := GetEnv("share.password_salt") if salt == "" { return "", errors.New("请配置PASSWORD_SALT") } diff --git a/backend/internal/utils/password_test.go b/backend/internal/utils/password_test.go index 000b1a6..6584560 100644 --- a/backend/internal/utils/password_test.go +++ b/backend/internal/utils/password_test.go @@ -9,8 +9,8 @@ import ( func TestGeneratePasswordHash(t *testing.T) { // 保存原始环境变量 - originalSalt := os.Getenv("password.salt") - defer os.Setenv("password.salt", originalSalt) + originalSalt := os.Getenv("share.password_salt") + defer os.Setenv("share.password_salt", originalSalt) tests := []struct { name string @@ -20,11 +20,11 @@ func TestGeneratePasswordHash(t *testing.T) { errorMsg string }{ { - name: "password.salt未配置", + name: "share.password_salt未配置", password: "testpassword", salt: "", expectError: true, - errorMsg: "请配置password.salt", + errorMsg: "请配置share.password_salt", }, { name: "正常生成哈希", @@ -38,9 +38,9 @@ func TestGeneratePasswordHash(t *testing.T) { t.Run(tt.name, func(t *testing.T) { // 设置环境变量 if tt.salt != "" { - os.Setenv("password.salt", tt.salt) + os.Setenv("share.password_salt", tt.salt) } else { - os.Unsetenv("password.salt") + os.Unsetenv("share.password_salt") } hash, err := GeneratePasswordHash(tt.password) diff --git a/backend/main.go b/backend/main.go index 44696df..652fda8 100644 --- a/backend/main.go +++ b/backend/main.go @@ -4,6 +4,7 @@ import ( "backend/internal/controllers" "backend/internal/utils" "backend/middleware" + "fmt" "github.com/labstack/echo/v4" "go.uber.org/zap" @@ -12,7 +13,7 @@ import ( func main() { // 日志 var logger *zap.Logger - if utils.GetEnvWithDefault("NODE_ENV", "production") == "production" { + if utils.GetEnvWithDefault("node.env", "production") == "production" { logger, _ = zap.NewProduction() } else { logger, _ = zap.NewDevelopment() @@ -40,5 +41,5 @@ func main() { e.GET("/image/compress/:id", controllers.GetCompressImage) e.GET("/stat", controllers.GetStat) - e.Logger.Fatal(e.Start(":1323")) + e.Logger.Fatal(e.Start(fmt.Sprintf(":%s", utils.GetEnvWithDefault("api.port", "5001")))) } From 1ed154913d9a230b613d9119a21d27774de47ba6 Mon Sep 17 00:00:00 2001 From: keven Date: Sun, 19 Oct 2025 00:10:09 +0800 Subject: [PATCH 3/5] refactor(backend,worker): update environment variable key for upload path to enhance consistency across modules --- backend/internal/utils/file.go | 2 +- worker/internal/utils/file.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/internal/utils/file.go b/backend/internal/utils/file.go index be7ec13..4b09b8f 100644 --- a/backend/internal/utils/file.go +++ b/backend/internal/utils/file.go @@ -41,7 +41,7 @@ func GetUploadDirPath() (string, error) { return "", err } finalPath := filepath.Join(basepath, "uploads") - uploadPath := GetEnvWithDefault("UPLOAD_PATH", finalPath) + uploadPath := GetEnvWithDefault("upload.path", finalPath) if err := os.MkdirAll(uploadPath, 0755); err != nil { return "", err } diff --git a/worker/internal/utils/file.go b/worker/internal/utils/file.go index c45e082..eeb2080 100644 --- a/worker/internal/utils/file.go +++ b/worker/internal/utils/file.go @@ -39,7 +39,7 @@ func GetUploadDirPath() (string, error) { return "", err } finalPath := filepath.Join(basepath, "uploads") - uploadPath := GetEnvWithDefault("UPLOAD_PATH", finalPath) + uploadPath := GetEnvWithDefault("upload.path", finalPath) if err := os.MkdirAll(uploadPath, 0755); err != nil { return "", err } From 50c0a14cc695f5fb7161048b4492837b734817d0 Mon Sep 17 00:00:00 2001 From: keven Date: Sun, 19 Oct 2025 00:26:12 +0800 Subject: [PATCH 4/5] feat(front): implement dynamic API base URL retrieval and enhance SEO metadata handling --- front/composables/useSeo.ts | 27 +++++++++++++++++---------- front/lib/getApiBaseUrl.ts | 5 +++++ front/nuxt.config.ts | 3 ++- 3 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 front/lib/getApiBaseUrl.ts diff --git a/front/composables/useSeo.ts b/front/composables/useSeo.ts index e700da2..fba1790 100644 --- a/front/composables/useSeo.ts +++ b/front/composables/useSeo.ts @@ -1,23 +1,30 @@ +import getApiBaseUrl from '~/lib/getApiBaseUrl' + type UseSeoProps = { head?: Record seo?: Record } const useSeo = async (props: UseSeoProps = {}) => { const { head, seo } = props || {} - const seoMeta = ref() + const seoMeta = ref<{ + site_title: string + site_desc: string + site_url: string + site_icon: string + site_bg_url: string + }>() if (import.meta.server) { - const { SITE_TITLE, SITE_DESC, SITE_URL } = process.env || {} - seoMeta.value = { - site_title: SITE_TITLE, - site_desc: SITE_DESC, - site_url: SITE_URL, - } + await fetch(`${getApiBaseUrl()}/config`) + .then((res) => res.json()) + .then(({ data }) => { + seoMeta.value = data + }) const { title } = head || {} useHead({ link: [ - { rel: 'icon', href: '/logo.png', sizes: 'any' }, + { rel: 'icon', href: seoMeta.value?.site_icon || '/logo.png', sizes: 'any' }, // { rel: 'icon', href: '/favicon.svg', sizes: 'any', type: 'image/svg+xml' }, - { rel: 'apple-touch-icon', sizes: '180x180', href: '/logo.png' }, + { rel: 'apple-touch-icon', sizes: '180x180', href: seoMeta.value?.site_icon || '/logo.png' }, ], meta: [ // used on some mobile browsers @@ -33,7 +40,7 @@ const useSeo = async (props: UseSeoProps = {}) => { ogTitle: seoMeta?.value?.site_title, ogDescription: seoMeta?.value?.site_desc, ogImage: { - url: `${seoMeta?.value?.site_url}/logo.png`, + url: `${seoMeta?.value?.site_url}${seoMeta?.value?.site_icon || '/logo.png'}`, width: 1024, height: 1024, alt: 'logo', diff --git a/front/lib/getApiBaseUrl.ts b/front/lib/getApiBaseUrl.ts new file mode 100644 index 0000000..d653a6d --- /dev/null +++ b/front/lib/getApiBaseUrl.ts @@ -0,0 +1,5 @@ +const getApiBaseUrl = () => { + return import.meta.env.API_BASE_URL?.replace(/\/$/, '') || 'http://127.0.0.1:5001' +} + +export default getApiBaseUrl diff --git a/front/nuxt.config.ts b/front/nuxt.config.ts index ca15b2c..05d2fc5 100644 --- a/front/nuxt.config.ts +++ b/front/nuxt.config.ts @@ -1,4 +1,5 @@ import tailwindcss from '@tailwindcss/vite' +import getApiBaseUrl from './lib/getApiBaseUrl' // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ compatibilityDate: '2024-04-03', @@ -35,7 +36,7 @@ export default defineNuxtConfig({ nitro: { routeRules: { '/api/**': { - proxy: process.env.API_BASE_URL || 'http://127.0.0.1:1323/**', + proxy: `${getApiBaseUrl()}/**`, }, }, }, From e6cc1b02296244611957ba32a8ef0afacca93908 Mon Sep 17 00:00:00 2001 From: keven Date: Sun, 19 Oct 2025 10:19:28 +0800 Subject: [PATCH 5/5] feat(backend): add About and Config controllers for dynamic environment variable retrieval --- backend/internal/controllers/about.go | 19 +++++++++++++++++++ backend/internal/controllers/config.go | 17 +++++++++++++++++ backend/internal/utils/env.go | 5 +++++ 3 files changed, 41 insertions(+) create mode 100644 backend/internal/controllers/about.go create mode 100644 backend/internal/controllers/config.go diff --git a/backend/internal/controllers/about.go b/backend/internal/controllers/about.go new file mode 100644 index 0000000..c8c54c5 --- /dev/null +++ b/backend/internal/controllers/about.go @@ -0,0 +1,19 @@ +package controllers + +import ( + "backend/internal/utils" + + "github.com/labstack/echo/v4" +) + +func GetAbout(c echo.Context) error { + + return utils.HTTPSuccessHandler(c, map[string]any{ + "bg_url": utils.GetEnv("about.bg_url"), + "content": utils.GetEnvMapString("about.content"), + "email": utils.GetEnv("about.email"), + "name": utils.GetEnv("about.name"), + "url": utils.GetEnv("about.url"), + "avatar": utils.GetEnv("about.avatar"), + }) +} diff --git a/backend/internal/controllers/config.go b/backend/internal/controllers/config.go new file mode 100644 index 0000000..a8ff51e --- /dev/null +++ b/backend/internal/controllers/config.go @@ -0,0 +1,17 @@ +package controllers + +import ( + "backend/internal/utils" + + "github.com/labstack/echo/v4" +) + +func GetConfig(c echo.Context) error { + return utils.HTTPSuccessHandler(c, map[string]any{ + "site_title": utils.GetEnvMapString("site.title"), + "site_desc": utils.GetEnvMapString("site.desc"), + "site_url": utils.GetEnv("site.url"), + "site_icon": utils.GetEnvWithDefault("site.icon", "/logo.png"), + "site_bg_url": utils.GetEnvWithDefault("site.bg_url", "https://img.fudaoyuan.icu/api/1/random/?scale_min=1.5&webp=true&md=false&format=302"), + }) +} diff --git a/backend/internal/utils/env.go b/backend/internal/utils/env.go index c13b89f..bd4ffdb 100644 --- a/backend/internal/utils/env.go +++ b/backend/internal/utils/env.go @@ -44,3 +44,8 @@ func GetEnvWithDefault(key string, defaultValue string) string { } return value } + +func GetEnvMapString(key string) map[string]string { + InitEnv() + return v.GetStringMapString(key) +}