[重构] 将多个 API 接口的请求方法从 PUT 和 DELETE 更改为 POST,并更新相关路由

This commit is contained in:
ryan
2026-03-17 09:57:38 +08:00
parent 2cdb844010
commit 2c17f3289b
18 changed files with 80 additions and 79 deletions
+1
View File
@@ -133,6 +133,7 @@
* 成功与失败都必须返回清晰 `message`
* Agent API 固定放在 `/api/agent/*`
* 总览与节点详情优先使用专用聚合接口
* 管理端变更类接口统一使用 `POST`;只读接口使用 `GET`
统一响应结构:
@@ -131,7 +131,7 @@ func PublishConfigVersion(c *gin.Context) {
// @Param id path int true "Version ID"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} map[string]interface{}
// @Router /api/config-versions/{id}/activate [put]
// @Router /api/config-versions/{id}/activate [post]
func ActivateConfigVersion(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil || id == 0 {
@@ -76,7 +76,7 @@ func CreateManagedDomain(c *gin.Context) {
// @Param payload body service.ManagedDomainInput true "Managed domain payload"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} map[string]interface{}
// @Router /api/managed-domains/{id} [put]
// @Router /api/managed-domains/{id}/update [post]
func UpdateManagedDomain(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil || id == 0 {
@@ -117,7 +117,7 @@ func UpdateManagedDomain(c *gin.Context) {
// @Param id path int true "Managed domain ID"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} map[string]interface{}
// @Router /api/managed-domains/{id} [delete]
// @Router /api/managed-domains/{id}/delete [post]
func DeleteManagedDomain(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil || id == 0 {
+2 -2
View File
@@ -84,7 +84,7 @@ func RotateNodeBootstrapToken(c *gin.Context) {
// @Param payload body service.NodeInput true "Node payload"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} map[string]interface{}
// @Router /api/nodes/{id} [put]
// @Router /api/nodes/{id}/update [post]
func UpdateNode(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil || id == 0 {
@@ -114,7 +114,7 @@ func UpdateNode(c *gin.Context) {
// @Param id path int true "Node ID"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} map[string]interface{}
// @Router /api/nodes/{id} [delete]
// @Router /api/nodes/{id}/delete [post]
func DeleteNode(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil || id == 0 {
+1 -1
View File
@@ -211,7 +211,7 @@ func GetOptions(c *gin.Context) {
// @Param payload body model.Option true "Option payload"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} map[string]interface{}
// @Router /api/option/ [put]
// @Router /api/option/update [post]
func UpdateOption(c *gin.Context) {
var option model.Option
err := json.NewDecoder(c.Request.Body).Decode(&option)
+2 -2
View File
@@ -75,7 +75,7 @@ func CreateProxyRoute(c *gin.Context) {
// @Param payload body service.ProxyRouteInput true "Proxy route payload"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} map[string]interface{}
// @Router /api/proxy-routes/{id} [put]
// @Router /api/proxy-routes/{id}/update [post]
func UpdateProxyRoute(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil || id == 0 {
@@ -116,7 +116,7 @@ func UpdateProxyRoute(c *gin.Context) {
// @Param id path int true "Route ID"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} map[string]interface{}
// @Router /api/proxy-routes/{id} [delete]
// @Router /api/proxy-routes/{id}/delete [post]
func DeleteProxyRoute(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil || id == 0 {
@@ -143,7 +143,7 @@ func CreateTLSCertificate(c *gin.Context) {
// @Param payload body service.TLSCertificateInput true "TLS certificate payload"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} map[string]interface{}
// @Router /api/tls-certificates/{id} [put]
// @Router /api/tls-certificates/{id}/update [post]
func UpdateTLSCertificate(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil || id == 0 {
@@ -233,7 +233,7 @@ func ImportTLSCertificateFile(c *gin.Context) {
// @Param id path int true "Certificate ID"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} map[string]interface{}
// @Router /api/tls-certificates/{id} [delete]
// @Router /api/tls-certificates/{id}/delete [post]
func DeleteTLSCertificate(c *gin.Context) {
id, err := strconv.ParseUint(c.Param("id"), 10, 64)
if err != nil || id == 0 {
+15 -15
View File
@@ -32,8 +32,8 @@ func SetApiRouter(router *gin.Engine) {
selfRoute.Use(middleware.UserAuth(), middleware.NoTokenAuth())
{
selfRoute.GET("/self", controller.GetSelf)
selfRoute.PUT("/self", controller.UpdateSelf)
selfRoute.DELETE("/self", controller.DeleteSelf)
selfRoute.POST("/self/update", controller.UpdateSelf)
selfRoute.POST("/self/delete", controller.DeleteSelf)
selfRoute.GET("/token", controller.GenerateToken)
}
@@ -45,15 +45,15 @@ func SetApiRouter(router *gin.Engine) {
adminRoute.GET("/:id", controller.GetUser)
adminRoute.POST("/", controller.CreateUser)
adminRoute.POST("/manage", controller.ManageUser)
adminRoute.PUT("/", controller.UpdateUser)
adminRoute.DELETE("/:id", controller.DeleteUser)
adminRoute.POST("/update", controller.UpdateUser)
adminRoute.POST("/:id/delete", controller.DeleteUser)
}
}
optionRoute := apiRouter.Group("/option")
optionRoute.Use(middleware.RootAuth(), middleware.NoTokenAuth())
{
optionRoute.GET("/", controller.GetOptions)
optionRoute.PUT("/", controller.UpdateOption)
optionRoute.POST("/update", controller.UpdateOption)
optionRoute.POST("/geoip/lookup", controller.LookupGeoIP)
}
updateRoute := apiRouter.Group("/update")
@@ -71,15 +71,15 @@ func SetApiRouter(router *gin.Engine) {
fileRoute.GET("/", controller.GetAllFiles)
fileRoute.GET("/search", controller.SearchFiles)
fileRoute.POST("/", middleware.UploadRateLimit(), controller.UploadFile)
fileRoute.DELETE("/:id", controller.DeleteFile)
fileRoute.POST("/:id/delete", controller.DeleteFile)
}
proxyRoute := apiRouter.Group("/proxy-routes")
proxyRoute.Use(middleware.AdminAuth())
{
proxyRoute.GET("/", controller.GetProxyRoutes)
proxyRoute.POST("/", controller.CreateProxyRoute)
proxyRoute.PUT("/:id", controller.UpdateProxyRoute)
proxyRoute.DELETE("/:id", controller.DeleteProxyRoute)
proxyRoute.POST("/:id/update", controller.UpdateProxyRoute)
proxyRoute.POST("/:id/delete", controller.DeleteProxyRoute)
}
managedDomainRoute := apiRouter.Group("/managed-domains")
managedDomainRoute.Use(middleware.AdminAuth())
@@ -87,8 +87,8 @@ func SetApiRouter(router *gin.Engine) {
managedDomainRoute.GET("/", controller.GetManagedDomains)
managedDomainRoute.GET("/match", controller.MatchManagedDomainCertificate)
managedDomainRoute.POST("/", controller.CreateManagedDomain)
managedDomainRoute.PUT("/:id", controller.UpdateManagedDomain)
managedDomainRoute.DELETE("/:id", controller.DeleteManagedDomain)
managedDomainRoute.POST("/:id/update", controller.UpdateManagedDomain)
managedDomainRoute.POST("/:id/delete", controller.DeleteManagedDomain)
}
tlsCertificateRoute := apiRouter.Group("/tls-certificates")
tlsCertificateRoute.Use(middleware.AdminAuth())
@@ -97,9 +97,9 @@ func SetApiRouter(router *gin.Engine) {
tlsCertificateRoute.GET("/:id", controller.GetTLSCertificate)
tlsCertificateRoute.GET("/:id/content", controller.GetTLSCertificateContent)
tlsCertificateRoute.POST("/", controller.CreateTLSCertificate)
tlsCertificateRoute.PUT("/:id", controller.UpdateTLSCertificate)
tlsCertificateRoute.POST("/:id/update", controller.UpdateTLSCertificate)
tlsCertificateRoute.POST("/import-file", controller.ImportTLSCertificateFile)
tlsCertificateRoute.DELETE("/:id", controller.DeleteTLSCertificate)
tlsCertificateRoute.POST("/:id/delete", controller.DeleteTLSCertificate)
}
configVersionRoute := apiRouter.Group("/config-versions")
configVersionRoute.Use(middleware.AdminAuth())
@@ -109,7 +109,7 @@ func SetApiRouter(router *gin.Engine) {
configVersionRoute.GET("/preview", controller.PreviewConfigVersion)
configVersionRoute.GET("/diff", controller.DiffConfigVersion)
configVersionRoute.POST("/publish", controller.PublishConfigVersion)
configVersionRoute.PUT("/:id/activate", controller.ActivateConfigVersion)
configVersionRoute.POST("/:id/activate", controller.ActivateConfigVersion)
}
dashboardRoute := apiRouter.Group("/dashboard")
dashboardRoute.Use(middleware.AdminAuth())
@@ -127,8 +127,8 @@ func SetApiRouter(router *gin.Engine) {
nodeRoute.GET("/:id/observability", controller.GetNodeObservability)
nodeRoute.POST("/:id/agent-update", controller.RequestNodeAgentUpdate)
nodeRoute.POST("/:id/openresty-restart", controller.RequestNodeOpenrestyRestart)
nodeRoute.PUT("/:id", controller.UpdateNode)
nodeRoute.DELETE("/:id", controller.DeleteNode)
nodeRoute.POST("/:id/update", controller.UpdateNode)
nodeRoute.POST("/:id/delete", controller.DeleteNode)
}
applyLogRoute := apiRouter.Group("/apply-logs")
applyLogRoute.Use(middleware.AdminAuth())
+6 -6
View File
@@ -110,7 +110,7 @@ func TestPhase1PublishLifecycle(t *testing.T) {
"remark": "updated route",
}
routePath := "/api/proxy-routes/" + toString(createdRoute.ID)
resp = performJSONRequest(t, engine, token, http.MethodPut, routePath, updateBody)
resp = performJSONRequest(t, engine, token, http.MethodPost, routePath+"/update", updateBody)
decodeResponseData(t, resp, &createdRoute)
if createdRoute.OriginURL != "https://origin-b.internal" {
t.Fatalf("unexpected updated route origin: %s", createdRoute.OriginURL)
@@ -141,7 +141,7 @@ func TestPhase1PublishLifecycle(t *testing.T) {
}
activatePath := "/api/config-versions/" + toString(version1.ID) + "/activate"
resp = performJSONRequest(t, engine, token, http.MethodPut, activatePath, nil)
resp = performJSONRequest(t, engine, token, http.MethodPost, activatePath, nil)
decodeResponseData(t, resp, &activeVersion)
if activeVersion.ID != version1.ID || !activeVersion.IsActive {
t.Fatal("expected version1 to become active after rollback activation")
@@ -162,7 +162,7 @@ func TestPhase1PublishLifecycle(t *testing.T) {
}
deletePath := "/api/proxy-routes/" + toString(createdRoute.ID)
resp = performJSONRequest(t, engine, token, http.MethodDelete, deletePath, nil)
resp = performJSONRequest(t, engine, token, http.MethodPost, deletePath+"/delete", nil)
if !resp.Success {
t.Fatalf("expected delete route success, got: %s", resp.Message)
}
@@ -210,7 +210,7 @@ func TestPhase1HTTPSAndCertificateImportLifecycle(t *testing.T) {
}
updatedCertPEM, updatedKeyPEM := generateCertificatePairForRouterTest(t, []string{"secure.example.com", "www.secure.example.com"})
updateCertificateResp := performJSONRequest(t, engine, token, http.MethodPut, "/api/tls-certificates/"+toString(manualCertificate.ID), map[string]any{
updateCertificateResp := performJSONRequest(t, engine, token, http.MethodPost, "/api/tls-certificates/"+toString(manualCertificate.ID)+"/update", map[string]any{
"name": "secure-example-updated",
"cert_pem": updatedCertPEM,
"key_pem": updatedKeyPEM,
@@ -250,7 +250,7 @@ func TestPhase1HTTPSAndCertificateImportLifecycle(t *testing.T) {
t.Fatal("expected route to persist https certificate binding")
}
updateResp := performJSONRequest(t, engine, token, http.MethodPut, "/api/proxy-routes/"+toString(route.ID), map[string]any{
updateResp := performJSONRequest(t, engine, token, http.MethodPost, "/api/proxy-routes/"+toString(route.ID)+"/update", map[string]any{
"domain": "secure.example.com",
"origin_url": "http://origin-secure.internal",
"enabled": true,
@@ -264,7 +264,7 @@ func TestPhase1HTTPSAndCertificateImportLifecycle(t *testing.T) {
t.Fatalf("expected route to disable https flags, got %+v", route)
}
updateResp = performJSONRequest(t, engine, token, http.MethodPut, "/api/proxy-routes/"+toString(route.ID), map[string]any{
updateResp = performJSONRequest(t, engine, token, http.MethodPost, "/api/proxy-routes/"+toString(route.ID)+"/update", map[string]any{
"domain": "secure.example.com",
"origin_url": "https://origin-secure.internal",
"enabled": true,
@@ -84,7 +84,7 @@ func TestPhase2ManagedDomainLifecycle(t *testing.T) {
t.Fatalf("expected exact certificate id %d, got %#v", exactID, candidate["certificate_id"])
}
updateResp := performJSONRequest(t, engine, token, http.MethodPut, "/api/managed-domains/"+toString(uint(exactDomain["id"].(float64))), map[string]any{
updateResp := performJSONRequest(t, engine, token, http.MethodPost, "/api/managed-domains/"+toString(uint(exactDomain["id"].(float64)))+"/update", map[string]any{
"domain": "api.example.com",
"cert_id": exactID,
"enabled": false,
@@ -105,7 +105,7 @@ func TestPhase2ManagedDomainLifecycle(t *testing.T) {
t.Fatalf("expected wildcard certificate id %d, got %#v", wildcardID, candidate["certificate_id"])
}
deleteResp := performJSONRequest(t, engine, token, http.MethodDelete, "/api/managed-domains/"+toString(uint(wildcardDomain["id"].(float64))), nil)
deleteResp := performJSONRequest(t, engine, token, http.MethodPost, "/api/managed-domains/"+toString(uint(wildcardDomain["id"].(float64)))+"/delete", nil)
if !deleteResp.Success {
t.Fatalf("expected delete success, got %s", deleteResp.Message)
}
+7 -7
View File
@@ -41,19 +41,19 @@ func TestPhase2RateLimitOptionsHotReload(t *testing.T) {
loginCookie := loginAsRoot(t, engine)
performSessionJSONRequest(t, engine, loginCookie, http.MethodPut, "/api/option/", map[string]any{
performSessionJSONRequest(t, engine, loginCookie, http.MethodPost, "/api/option/update", map[string]any{
"key": "GlobalApiRateLimitNum",
"value": "450",
})
performSessionJSONRequest(t, engine, loginCookie, http.MethodPut, "/api/option/", map[string]any{
performSessionJSONRequest(t, engine, loginCookie, http.MethodPost, "/api/option/update", map[string]any{
"key": "GlobalApiRateLimitDuration",
"value": "240",
})
performSessionJSONRequest(t, engine, loginCookie, http.MethodPut, "/api/option/", map[string]any{
performSessionJSONRequest(t, engine, loginCookie, http.MethodPost, "/api/option/update", map[string]any{
"key": "CriticalRateLimitNum",
"value": "150",
})
performSessionJSONRequest(t, engine, loginCookie, http.MethodPut, "/api/option/", map[string]any{
performSessionJSONRequest(t, engine, loginCookie, http.MethodPost, "/api/option/update", map[string]any{
"key": "CriticalRateLimitDuration",
"value": "900",
})
@@ -330,7 +330,7 @@ func TestPhase2AgentLifecycle(t *testing.T) {
t.Fatalf("expected 2 apply logs, got %d", len(logs))
}
updatedNodeResp := performJSONRequest(t, engine, adminToken, http.MethodPut, "/api/nodes/"+toString(createdNode.ID), map[string]any{
updatedNodeResp := performJSONRequest(t, engine, adminToken, http.MethodPost, "/api/nodes/"+toString(createdNode.ID)+"/update", map[string]any{
"name": "shanghai-edge-1-renamed",
"geo_manual_override": true,
"geo_name": "Tokyo",
@@ -355,7 +355,7 @@ func TestPhase2AgentLifecycle(t *testing.T) {
t.Fatal("expected node to be shown as offline after timeout")
}
deleteResp := performJSONRequest(t, engine, adminToken, http.MethodDelete, "/api/nodes/"+toString(createdNode.ID), nil)
deleteResp := performJSONRequest(t, engine, adminToken, http.MethodPost, "/api/nodes/"+toString(createdNode.ID)+"/delete", nil)
if !deleteResp.Success {
t.Fatalf("expected delete node success, got %s", deleteResp.Message)
}
@@ -401,7 +401,7 @@ func TestPhase2CustomHeadersPreviewAndDiffLifecycle(t *testing.T) {
performJSONRequest(t, engine, token, http.MethodPost, "/api/config-versions/publish", nil)
performJSONRequest(t, engine, token, http.MethodPut, "/api/proxy-routes/"+toString(createdRoute.ID), map[string]any{
performJSONRequest(t, engine, token, http.MethodPost, "/api/proxy-routes/"+toString(createdRoute.ID)+"/update", map[string]any{
"domain": "preview.example.com",
"origin_url": "https://origin-b.internal",
"origin_host": "preview-upstream.internal",
@@ -24,8 +24,8 @@ export function publishConfigVersion() {
});
}
export function activateConfigVersion(id: number) {
return apiRequest<ConfigVersionItem>(`/config-versions/${id}/activate`, {
method: 'PUT',
});
}
export function activateConfigVersion(id: number) {
return apiRequest<ConfigVersionItem>(`/config-versions/${id}/activate`, {
method: 'POST',
});
}
@@ -18,15 +18,15 @@ export function createManagedDomain(payload: ManagedDomainMutationPayload) {
}
export function updateManagedDomain(id: number, payload: ManagedDomainMutationPayload) {
return apiRequest<ManagedDomainItem>(`/managed-domains/${id}`, {
method: 'PUT',
return apiRequest<ManagedDomainItem>(`/managed-domains/${id}/update`, {
method: 'POST',
body: JSON.stringify(payload),
});
}
export function deleteManagedDomain(id: number) {
return apiRequest<void>(`/managed-domains/${id}`, {
method: 'DELETE',
return apiRequest<void>(`/managed-domains/${id}/delete`, {
method: 'POST',
});
}
@@ -22,15 +22,15 @@ export function createNode(payload: NodeMutationPayload) {
}
export function updateNode(id: number, payload: NodeMutationPayload) {
return apiRequest<NodeItem>(`/nodes/${id}`, {
method: 'PUT',
return apiRequest<NodeItem>(`/nodes/${id}/update`, {
method: 'POST',
body: JSON.stringify(payload),
});
}
export function deleteNode(id: number) {
return apiRequest<void>(`/nodes/${id}`, {
method: 'DELETE',
return apiRequest<void>(`/nodes/${id}/delete`, {
method: 'POST',
});
}
@@ -18,18 +18,18 @@ export function createProxyRoute(payload: ProxyRouteMutationPayload) {
});
}
export function updateProxyRoute(id: number, payload: ProxyRouteMutationPayload) {
return apiRequest<ProxyRouteItem>(`/proxy-routes/${id}`, {
method: 'PUT',
body: JSON.stringify(payload),
});
}
export function deleteProxyRoute(id: number) {
return apiRequest<void>(`/proxy-routes/${id}`, {
method: 'DELETE',
});
}
export function updateProxyRoute(id: number, payload: ProxyRouteMutationPayload) {
return apiRequest<ProxyRouteItem>(`/proxy-routes/${id}/update`, {
method: 'POST',
body: JSON.stringify(payload),
});
}
export function deleteProxyRoute(id: number) {
return apiRequest<void>(`/proxy-routes/${id}/delete`, {
method: 'POST',
});
}
export function getTlsCertificates() {
return apiRequest<TlsCertificateItem[]>('/tls-certificates/');
@@ -13,8 +13,8 @@ export function getOptions() {
}
export function updateOption(key: string, value: string) {
return apiRequest<void>('/option/', {
method: 'PUT',
return apiRequest<void>('/option/update', {
method: 'POST',
body: JSON.stringify({ key, value }),
});
}
@@ -41,8 +41,8 @@ export function getSettingsProfile() {
}
export function updateSelf(payload: UpdateSelfPayload) {
return apiRequest<void>('/user/self', {
method: 'PUT',
return apiRequest<void>('/user/self/update', {
method: 'POST',
body: JSON.stringify(payload),
});
}
@@ -31,8 +31,8 @@ export function updateTlsCertificate(
id: number,
payload: TlsCertificateMutationPayload,
) {
return apiRequest<TlsCertificateItem>(`/tls-certificates/${id}`, {
method: 'PUT',
return apiRequest<TlsCertificateItem>(`/tls-certificates/${id}/update`, {
method: 'POST',
body: JSON.stringify(payload),
});
}
@@ -51,7 +51,7 @@ export function importTlsCertificateFiles(payload: TlsCertificateFileImportPaylo
}
export function deleteTlsCertificate(id: number) {
return apiRequest<void>(`/tls-certificates/${id}`, {
method: 'DELETE',
return apiRequest<void>(`/tls-certificates/${id}/delete`, {
method: 'POST',
});
}
@@ -26,12 +26,12 @@ export function createUser(payload: UserMutationPayload) {
});
}
export function updateUser(payload: UserMutationPayload & { id: number }) {
return apiRequest<void>('/user/', {
method: 'PUT',
body: JSON.stringify(payload),
});
}
export function updateUser(payload: UserMutationPayload & { id: number }) {
return apiRequest<void>('/user/update', {
method: 'POST',
body: JSON.stringify(payload),
});
}
export function manageUser(username: string, action: ManageUserAction) {
return apiRequest<ManageUserResult>('/user/manage', {