Update: 将子项目从 submodule 转为完整内容
- 移除 GovAI, nomifun-tauri, 算力盒子 的 submodule 引用 - 添加所有子项目的完整源代码 - 保留原始 .git 为 .git.bak 备份
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
package response
|
||||
|
||||
import "net/http"
|
||||
|
||||
// 错误码枚举,统一业务错误定义
|
||||
type ErrCode int
|
||||
|
||||
const (
|
||||
// 通用错误 (0xxxx)
|
||||
ErrCodeSuccess ErrCode = 0
|
||||
ErrCodeBadRequest ErrCode = 40001
|
||||
ErrCodeUnauthorized ErrCode = 40101
|
||||
ErrCodeForbidden ErrCode = 40301
|
||||
ErrCodeNotFound ErrCode = 40401
|
||||
ErrCodeRequestTimeout ErrCode = 40801
|
||||
ErrCodeTooManyRequests ErrCode = 42901
|
||||
ErrCodeInternalError ErrCode = 50001
|
||||
ErrCodeServiceUnavailable ErrCode = 50301
|
||||
ErrCodeGatewayTimeout ErrCode = 50401
|
||||
|
||||
// 业务错误 (6xxxx)
|
||||
ErrCodeInvalidToken ErrCode = 40102
|
||||
ErrCodeTokenExpired ErrCode = 40103
|
||||
ErrCodeUserDisabled ErrCode = 40104
|
||||
ErrCodeOrgNotFound ErrCode = 40402
|
||||
ErrCodeAppNotFound ErrCode = 40403
|
||||
ErrCodeKnowledgeNotFound ErrCode = 40404
|
||||
ErrCodeInsufficientQuota ErrCode = 42902
|
||||
ErrCodeFileTooLarge ErrCode = 40002
|
||||
ErrCodeInvalidFileType ErrCode = 40003
|
||||
)
|
||||
|
||||
var httpStatusMap = map[ErrCode]int{
|
||||
ErrCodeSuccess: http.StatusOK,
|
||||
ErrCodeBadRequest: http.StatusBadRequest,
|
||||
ErrCodeUnauthorized: http.StatusUnauthorized,
|
||||
ErrCodeForbidden: http.StatusForbidden,
|
||||
ErrCodeNotFound: http.StatusNotFound,
|
||||
ErrCodeRequestTimeout: http.StatusRequestTimeout,
|
||||
ErrCodeTooManyRequests: http.StatusTooManyRequests,
|
||||
ErrCodeInternalError: http.StatusInternalServerError,
|
||||
ErrCodeServiceUnavailable: http.StatusServiceUnavailable,
|
||||
ErrCodeGatewayTimeout: http.StatusGatewayTimeout,
|
||||
ErrCodeInvalidToken: http.StatusUnauthorized,
|
||||
ErrCodeTokenExpired: http.StatusUnauthorized,
|
||||
ErrCodeUserDisabled: http.StatusUnauthorized,
|
||||
ErrCodeOrgNotFound: http.StatusNotFound,
|
||||
ErrCodeAppNotFound: http.StatusNotFound,
|
||||
ErrCodeKnowledgeNotFound: http.StatusNotFound,
|
||||
ErrCodeInsufficientQuota: http.StatusTooManyRequests,
|
||||
ErrCodeFileTooLarge: http.StatusBadRequest,
|
||||
ErrCodeInvalidFileType: http.StatusBadRequest,
|
||||
}
|
||||
|
||||
func (e ErrCode) Status() int {
|
||||
if s, ok := httpStatusMap[e]; ok {
|
||||
return s
|
||||
}
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
|
||||
func (e ErrCode) Code() int {
|
||||
return int(e)
|
||||
}
|
||||
|
||||
func (e ErrCode) Error() string {
|
||||
return e.String()
|
||||
}
|
||||
|
||||
func (e ErrCode) String() string {
|
||||
switch e {
|
||||
case ErrCodeSuccess: return "成功"
|
||||
case ErrCodeBadRequest: return "请求参数有误"
|
||||
case ErrCodeUnauthorized: return "未授权"
|
||||
case ErrCodeForbidden: return "无权限"
|
||||
case ErrCodeNotFound: return "资源不存在"
|
||||
case ErrCodeRequestTimeout: return "请求超时"
|
||||
case ErrCodeTooManyRequests: return "请求过于频繁"
|
||||
case ErrCodeInternalError: return "服务器内部错误"
|
||||
case ErrCodeServiceUnavailable: return "服务不可用"
|
||||
case ErrCodeGatewayTimeout: return "网关超时"
|
||||
case ErrCodeInvalidToken: return "无效的认证令牌"
|
||||
case ErrCodeTokenExpired: return "认证令牌已过期"
|
||||
case ErrCodeUserDisabled: return "用户已被禁用"
|
||||
case ErrCodeOrgNotFound: return "机构不存在"
|
||||
case ErrCodeAppNotFound: return "应用不存在"
|
||||
case ErrCodeKnowledgeNotFound: return "知识库不存在"
|
||||
case ErrCodeInsufficientQuota: return "配额不足"
|
||||
case ErrCodeFileTooLarge: return "文件超出大小限制"
|
||||
case ErrCodeInvalidFileType: return "不支持的文件类型"
|
||||
default: return "未知错误"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package response
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type APIResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data any `json:"data"`
|
||||
}
|
||||
|
||||
func JSON(w http.ResponseWriter, status int, data any) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(status)
|
||||
json.NewEncoder(w).Encode(APIResponse{
|
||||
Code: 0,
|
||||
Message: "success",
|
||||
Data: data,
|
||||
})
|
||||
}
|
||||
|
||||
func Error(w http.ResponseWriter, status int, code int, message string) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(status)
|
||||
json.NewEncoder(w).Encode(APIResponse{
|
||||
Code: code,
|
||||
Message: message,
|
||||
Data: nil,
|
||||
})
|
||||
}
|
||||
|
||||
func BadRequest(w http.ResponseWriter, message string) {
|
||||
Error(w, http.StatusBadRequest, 40001, message)
|
||||
}
|
||||
|
||||
func Unauthorized(w http.ResponseWriter, message string) {
|
||||
Error(w, http.StatusUnauthorized, 40101, message)
|
||||
}
|
||||
|
||||
func Forbidden(w http.ResponseWriter, message string) {
|
||||
Error(w, http.StatusForbidden, 40301, message)
|
||||
}
|
||||
|
||||
func NotFound(w http.ResponseWriter, message string) {
|
||||
Error(w, http.StatusNotFound, 40401, message)
|
||||
}
|
||||
|
||||
func InternalError(w http.ResponseWriter, message string) {
|
||||
Error(w, http.StatusInternalServerError, 50001, message)
|
||||
}
|
||||
|
||||
func TooManyRequests(w http.ResponseWriter, message string) {
|
||||
Error(w, http.StatusTooManyRequests, 42901, message)
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package response
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestJSON(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
data := map[string]string{"key": "value"}
|
||||
JSON(w, http.StatusOK, data)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("status = %d, want %d", w.Code, http.StatusOK)
|
||||
}
|
||||
if ct := w.Header().Get("Content-Type"); ct != "application/json" {
|
||||
t.Errorf("Content-Type = %s, want application/json", ct)
|
||||
}
|
||||
|
||||
var resp APIResponse
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
|
||||
t.Fatalf("failed to unmarshal: %v", err)
|
||||
}
|
||||
if resp.Code != 0 {
|
||||
t.Errorf("code = %d, want 0", resp.Code)
|
||||
}
|
||||
if resp.Message != "success" {
|
||||
t.Errorf("message = %s, want success", resp.Message)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadRequest(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
BadRequest(w, "参数错误")
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("status = %d, want %d", w.Code, http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnauthorized(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
Unauthorized(w, "未登录")
|
||||
if w.Code != http.StatusUnauthorized {
|
||||
t.Errorf("status = %d, want %d", w.Code, http.StatusUnauthorized)
|
||||
}
|
||||
}
|
||||
|
||||
func TestForbidden(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
Forbidden(w, "无权限")
|
||||
if w.Code != http.StatusForbidden {
|
||||
t.Errorf("status = %d, want %d", w.Code, http.StatusForbidden)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotFound(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
NotFound(w, "资源不存在")
|
||||
if w.Code != http.StatusNotFound {
|
||||
t.Errorf("status = %d, want %d", w.Code, http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInternalError(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
InternalError(w, "内部错误")
|
||||
if w.Code != http.StatusInternalServerError {
|
||||
t.Errorf("status = %d, want %d", w.Code, http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTooManyRequests(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
TooManyRequests(w, "过于频繁")
|
||||
if w.Code != http.StatusTooManyRequests {
|
||||
t.Errorf("status = %d, want %d", w.Code, http.StatusTooManyRequests)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user