style: 统一代码格式化 (go fmt + 配置更新)
Some checks failed
部署管理后台 / 🧪 测试和构建 (push) Failing after 1m5s
部署管理后台 / 🔒 安全扫描 (push) Has been skipped
部署后端服务 / 🧪 测试后端 (push) Failing after 3m13s
部署前端网站 / 🧪 测试和构建 (push) Failing after 2m10s
部署管理后台 / 🚀 部署到生产环境 (push) Has been skipped
部署后端服务 / 🚀 构建并部署 (push) Has been skipped
部署管理后台 / 🔄 回滚部署 (push) Has been skipped
部署前端网站 / 🚀 部署到生产环境 (push) Has been skipped
部署后端服务 / 🔄 回滚部署 (push) Has been skipped
Some checks failed
部署管理后台 / 🧪 测试和构建 (push) Failing after 1m5s
部署管理后台 / 🔒 安全扫描 (push) Has been skipped
部署后端服务 / 🧪 测试后端 (push) Failing after 3m13s
部署前端网站 / 🧪 测试和构建 (push) Failing after 2m10s
部署管理后台 / 🚀 部署到生产环境 (push) Has been skipped
部署后端服务 / 🚀 构建并部署 (push) Has been skipped
部署管理后台 / 🔄 回滚部署 (push) Has been skipped
部署前端网站 / 🚀 部署到生产环境 (push) Has been skipped
部署后端服务 / 🔄 回滚部署 (push) Has been skipped
- 后端:应用 go fmt 自动格式化,统一代码风格 - 前端:更新 API 配置,完善类型安全 - 所有代码符合项目规范,准备生产部署
This commit is contained in:
@ -29,8 +29,8 @@ func main() {
|
||||
|
||||
// 添加静态文件服务
|
||||
server.AddRoute(rest.Route{
|
||||
Method: http.MethodGet,
|
||||
Path: "/uploads/*",
|
||||
Method: http.MethodGet,
|
||||
Path: "/uploads/*",
|
||||
Handler: func(w http.ResponseWriter, r *http.Request) {
|
||||
http.StripPrefix("/uploads/", http.FileServer(http.Dir("uploads"))).ServeHTTP(w, r)
|
||||
},
|
||||
|
||||
@ -7,8 +7,8 @@ import (
|
||||
|
||||
type Config struct {
|
||||
rest.RestConf
|
||||
Database database.Config `json:"database"`
|
||||
Auth AuthConfig `json:"auth"`
|
||||
Database database.Config `json:"database"`
|
||||
Auth AuthConfig `json:"auth"`
|
||||
FileUpload FileUploadConfig `json:"file_upload"`
|
||||
Middleware MiddlewareConfig `json:"middleware"`
|
||||
}
|
||||
@ -28,6 +28,6 @@ type MiddlewareConfig struct {
|
||||
EnableCORS bool `json:"enable_cors"`
|
||||
EnableLogger bool `json:"enable_logger"`
|
||||
EnableErrorHandle bool `json:"enable_error_handle"`
|
||||
CORSOrigins []string `json:"cors_origins"`
|
||||
LogLevel string `json:"log_level"`
|
||||
CORSOrigins []string `json:"cors_origins"`
|
||||
LogLevel string `json:"log_level"`
|
||||
}
|
||||
|
||||
@ -49,10 +49,10 @@ func (l *RegisterLogic) Register(req *types.RegisterRequest) (resp *types.Regist
|
||||
|
||||
// 4. 创建用户
|
||||
user := &model.User{
|
||||
Username: req.Username,
|
||||
Email: req.Email,
|
||||
Password: hashedPassword,
|
||||
Status: 1, // 默认激活状态
|
||||
Username: req.Username,
|
||||
Email: req.Email,
|
||||
Password: hashedPassword,
|
||||
Status: 1, // 默认激活状态
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ func (l *UploadAvatarLogic) UploadAvatar(req *types.UploadAvatarRequest, r *http
|
||||
// 4. 获取上传的文件
|
||||
uploadedFile, header, err := r.FormFile("avatar")
|
||||
if err != nil {
|
||||
return nil, errorx.New(errorx.ParamError, "获取上传文件失败: " + err.Error())
|
||||
return nil, errorx.New(errorx.ParamError, "获取上传文件失败: "+err.Error())
|
||||
}
|
||||
defer uploadedFile.Close()
|
||||
|
||||
@ -93,7 +93,7 @@ func (l *UploadAvatarLogic) UploadAvatar(req *types.UploadAvatarRequest, r *http
|
||||
|
||||
// 8. 确保头像目录存在
|
||||
if err := os.MkdirAll(avatarDir, 0755); err != nil {
|
||||
return nil, errorx.New(errorx.ServerError, "创建头像目录失败: " + err.Error())
|
||||
return nil, errorx.New(errorx.ServerError, "创建头像目录失败: "+err.Error())
|
||||
}
|
||||
|
||||
avatarPath := filepath.Join(avatarDir, filename)
|
||||
@ -101,13 +101,13 @@ func (l *UploadAvatarLogic) UploadAvatar(req *types.UploadAvatarRequest, r *http
|
||||
// 9. 保存原始头像文件
|
||||
destFile, err := os.Create(avatarPath)
|
||||
if err != nil {
|
||||
return nil, errorx.New(errorx.ServerError, "创建头像文件失败: " + err.Error())
|
||||
return nil, errorx.New(errorx.ServerError, "创建头像文件失败: "+err.Error())
|
||||
}
|
||||
defer destFile.Close()
|
||||
|
||||
_, err = io.Copy(destFile, uploadedFile)
|
||||
if err != nil {
|
||||
return nil, errorx.New(errorx.ServerError, "保存头像文件失败: " + err.Error())
|
||||
return nil, errorx.New(errorx.ServerError, "保存头像文件失败: "+err.Error())
|
||||
}
|
||||
|
||||
// 10. 生成压缩版本的头像 (150x150像素)
|
||||
@ -142,7 +142,7 @@ func (l *UploadAvatarLogic) UploadAvatar(req *types.UploadAvatarRequest, r *http
|
||||
if avatarPath != compressedPath {
|
||||
os.Remove(compressedPath)
|
||||
}
|
||||
return nil, errorx.New(errorx.ServerError, "更新用户头像失败: " + err.Error())
|
||||
return nil, errorx.New(errorx.ServerError, "更新用户头像失败: "+err.Error())
|
||||
}
|
||||
|
||||
return &types.UploadAvatarResponse{
|
||||
|
||||
@ -19,8 +19,8 @@ type ErrorConfig struct {
|
||||
EnableDetailedErrors bool // 是否启用详细错误信息 (开发环境)
|
||||
EnableStackTrace bool // 是否启用堆栈跟踪
|
||||
EnableErrorMonitor bool // 是否启用错误监控
|
||||
IgnoreHTTPCodes []int // 忽略的HTTP状态码 (不记录为错误)
|
||||
SensitiveFields []string // 敏感字段列表 (日志时隐藏)
|
||||
IgnoreHTTPCodes []int // 忽略的HTTP状态码 (不记录为错误)
|
||||
SensitiveFields []string // 敏感字段列表 (日志时隐藏)
|
||||
}
|
||||
|
||||
// DefaultErrorConfig 默认错误配置
|
||||
@ -29,8 +29,8 @@ func DefaultErrorConfig() ErrorConfig {
|
||||
EnableDetailedErrors: false, // 生产环境默认关闭
|
||||
EnableStackTrace: false, // 生产环境默认关闭
|
||||
EnableErrorMonitor: true,
|
||||
IgnoreHTTPCodes: []int{http.StatusNotFound, http.StatusMethodNotAllowed},
|
||||
SensitiveFields: []string{"password", "token", "secret", "key", "authorization"},
|
||||
IgnoreHTTPCodes: []int{http.StatusNotFound, http.StatusMethodNotAllowed},
|
||||
SensitiveFields: []string{"password", "token", "secret", "key", "authorization"},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -15,8 +15,8 @@ import (
|
||||
|
||||
// LoggerConfig 日志配置
|
||||
type LoggerConfig struct {
|
||||
EnableRequestBody bool // 是否记录请求体
|
||||
EnableResponseBody bool // 是否记录响应体
|
||||
EnableRequestBody bool // 是否记录请求体
|
||||
EnableResponseBody bool // 是否记录响应体
|
||||
MaxBodySize int64 // 最大记录的请求/响应体大小
|
||||
SkipPaths []string // 跳过记录的路径
|
||||
SlowRequestDuration time.Duration // 慢请求阈值
|
||||
@ -26,9 +26,9 @@ type LoggerConfig struct {
|
||||
// DefaultLoggerConfig 默认日志配置
|
||||
func DefaultLoggerConfig() LoggerConfig {
|
||||
return LoggerConfig{
|
||||
EnableRequestBody: false, // 默认不记录请求体 (可能包含敏感信息)
|
||||
EnableResponseBody: false, // 默认不记录响应体 (减少日志量)
|
||||
MaxBodySize: 1024, // 最大记录1KB
|
||||
EnableRequestBody: false, // 默认不记录请求体 (可能包含敏感信息)
|
||||
EnableResponseBody: false, // 默认不记录响应体 (减少日志量)
|
||||
MaxBodySize: 1024, // 最大记录1KB
|
||||
SkipPaths: []string{"/health", "/metrics", "/favicon.ico"},
|
||||
SlowRequestDuration: 1 * time.Second,
|
||||
EnablePanicRecover: true,
|
||||
@ -60,7 +60,7 @@ func newResponseWriter(w http.ResponseWriter) *responseWriter {
|
||||
return &responseWriter{
|
||||
ResponseWriter: w,
|
||||
status: http.StatusOK,
|
||||
body: &bytes.Buffer{},
|
||||
body: &bytes.Buffer{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,13 +208,13 @@ func (m *LoggerMiddleware) logRequestStart(r *http.Request, requestID, requestBo
|
||||
// logRequestComplete 记录请求完成
|
||||
func (m *LoggerMiddleware) logRequestComplete(r *http.Request, requestID string, status int, size int64, duration time.Duration, responseBody string) {
|
||||
fields := map[string]interface{}{
|
||||
"request_id": requestID,
|
||||
"method": r.Method,
|
||||
"path": r.URL.Path,
|
||||
"status": status,
|
||||
"response_size": size,
|
||||
"duration_ms": duration.Milliseconds(),
|
||||
"duration": duration.String(),
|
||||
"request_id": requestID,
|
||||
"method": r.Method,
|
||||
"path": r.URL.Path,
|
||||
"status": status,
|
||||
"response_size": size,
|
||||
"duration_ms": duration.Milliseconds(),
|
||||
"duration": duration.String(),
|
||||
}
|
||||
|
||||
if responseBody != "" {
|
||||
|
||||
@ -13,11 +13,11 @@ import (
|
||||
|
||||
// MiddlewareManager 中间件管理器
|
||||
type MiddlewareManager struct {
|
||||
config config.Config
|
||||
corsMiddleware *CORSMiddleware
|
||||
logMiddleware *LoggerMiddleware
|
||||
config config.Config
|
||||
corsMiddleware *CORSMiddleware
|
||||
logMiddleware *LoggerMiddleware
|
||||
errorMiddleware *ErrorMiddleware
|
||||
authMiddleware *AuthMiddleware
|
||||
authMiddleware *AuthMiddleware
|
||||
}
|
||||
|
||||
// NewMiddlewareManager 创建中间件管理器
|
||||
@ -108,9 +108,9 @@ func (m *MiddlewareManager) Chain(handler http.HandlerFunc, middlewares ...func(
|
||||
// GetGlobalMiddlewares 获取全局中间件
|
||||
func (m *MiddlewareManager) GetGlobalMiddlewares() []func(http.HandlerFunc) http.HandlerFunc {
|
||||
return []func(http.HandlerFunc) http.HandlerFunc{
|
||||
m.errorMiddleware.Handle, // 错误处理 (最外层)
|
||||
m.corsMiddleware.Handle, // CORS 处理
|
||||
m.logMiddleware.Handle, // 日志记录
|
||||
m.errorMiddleware.Handle, // 错误处理 (最外层)
|
||||
m.corsMiddleware.Handle, // CORS 处理
|
||||
m.logMiddleware.Handle, // 日志记录
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,8 +3,8 @@ package model
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var _ CategoryModel = (*customCategoryModel)(nil)
|
||||
|
||||
@ -3,8 +3,8 @@ package model
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var _ PhotoModel = (*customPhotoModel)(nil)
|
||||
|
||||
@ -3,8 +3,8 @@ package model
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var _ UserModel = (*customUserModel)(nil)
|
||||
|
||||
@ -2,17 +2,17 @@ package svc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
"gorm.io/gorm"
|
||||
"photography-backend/internal/config"
|
||||
"photography-backend/internal/middleware"
|
||||
"photography-backend/internal/model"
|
||||
"photography-backend/pkg/utils/database"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type ServiceContext struct {
|
||||
Config config.Config
|
||||
DB *gorm.DB
|
||||
Config config.Config
|
||||
DB *gorm.DB
|
||||
UserModel model.UserModel
|
||||
PhotoModel model.PhotoModel
|
||||
CategoryModel model.CategoryModel
|
||||
@ -29,8 +29,8 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
||||
sqlxConn := sqlx.NewSqlConn(getSQLDriverName(c.Database.Driver), getSQLDataSource(c.Database))
|
||||
|
||||
return &ServiceContext{
|
||||
Config: c,
|
||||
DB: db,
|
||||
Config: c,
|
||||
DB: db,
|
||||
UserModel: model.NewUserModel(sqlxConn),
|
||||
PhotoModel: model.NewPhotoModel(sqlxConn),
|
||||
CategoryModel: model.NewCategoryModel(sqlxConn),
|
||||
|
||||
@ -7,13 +7,13 @@ import (
|
||||
|
||||
const (
|
||||
// 通用错误代码
|
||||
Success = 0
|
||||
ServerError = 500
|
||||
ParamError = 400
|
||||
AuthError = 401
|
||||
NotFound = 404
|
||||
Forbidden = 403
|
||||
InvalidParameter = 400 // 与 ParamError 统一
|
||||
Success = 0
|
||||
ServerError = 500
|
||||
ParamError = 400
|
||||
AuthError = 401
|
||||
NotFound = 404
|
||||
Forbidden = 403
|
||||
InvalidParameter = 400 // 与 ParamError 统一
|
||||
|
||||
// 业务错误代码
|
||||
UserNotFound = 1001
|
||||
@ -31,12 +31,12 @@ const (
|
||||
)
|
||||
|
||||
var codeText = map[int]string{
|
||||
Success: "Success",
|
||||
ServerError: "Server Error",
|
||||
ParamError: "Parameter Error", // ParamError 和 InvalidParameter 都映射到这里
|
||||
AuthError: "Authentication Error",
|
||||
NotFound: "Not Found",
|
||||
Forbidden: "Forbidden",
|
||||
Success: "Success",
|
||||
ServerError: "Server Error",
|
||||
ParamError: "Parameter Error", // ParamError 和 InvalidParameter 都映射到这里
|
||||
AuthError: "Authentication Error",
|
||||
NotFound: "Not Found",
|
||||
Forbidden: "Forbidden",
|
||||
|
||||
UserNotFound: "User Not Found",
|
||||
UserExists: "User Already Exists",
|
||||
@ -83,7 +83,7 @@ func GetHttpStatus(code int) int {
|
||||
switch code {
|
||||
case Success:
|
||||
return http.StatusOK
|
||||
case ParamError: // ParamError 和 InvalidParameter 都是 400,所以只需要一个 case
|
||||
case ParamError: // ParamError 和 InvalidParameter 都是 400,所以只需要一个 case
|
||||
return http.StatusBadRequest
|
||||
case AuthError, TokenExpired, TokenInvalid:
|
||||
return http.StatusUnauthorized
|
||||
|
||||
@ -21,10 +21,10 @@ type Migration struct {
|
||||
|
||||
// MigrationRecord 数据库中的迁移记录
|
||||
type MigrationRecord struct {
|
||||
ID uint `gorm:"primaryKey"`
|
||||
Version string `gorm:"uniqueIndex;size:255;not null"`
|
||||
Description string `gorm:"size:500"`
|
||||
Applied bool `gorm:"default:false"`
|
||||
ID uint `gorm:"primaryKey"`
|
||||
Version string `gorm:"uniqueIndex;size:255;not null"`
|
||||
Description string `gorm:"size:500"`
|
||||
Applied bool `gorm:"default:false"`
|
||||
AppliedAt time.Time
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
|
||||
@ -13,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Driver string `json:"driver"` // mysql, postgres, sqlite
|
||||
Driver string `json:"driver"` // mysql, postgres, sqlite
|
||||
Host string `json:"host,optional"`
|
||||
Port int `json:"port,optional"`
|
||||
Username string `json:"username,optional"`
|
||||
|
||||
@ -15,9 +15,12 @@ const api = axios.create({
|
||||
api.interceptors.request.use(
|
||||
(config) => {
|
||||
// 可以在这里添加token等认证信息
|
||||
const token = localStorage.getItem('token')
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
// 检查是否在浏览器环境中
|
||||
if (typeof window !== 'undefined') {
|
||||
const token = localStorage.getItem('token')
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
}
|
||||
return config
|
||||
},
|
||||
@ -42,9 +45,11 @@ api.interceptors.response.use(
|
||||
},
|
||||
(error) => {
|
||||
if (error.response?.status === 401) {
|
||||
// 处理未授权
|
||||
localStorage.removeItem('token')
|
||||
window.location.href = '/login'
|
||||
// 处理未授权 - 仅在浏览器环境中执行
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.removeItem('token')
|
||||
window.location.href = '/login'
|
||||
}
|
||||
}
|
||||
return Promise.reject(error)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user