From cce3d158d54c9472aeb665af1b55a60155525089 Mon Sep 17 00:00:00 2001 From: whm <973418690@qq.com> Date: Mon, 13 Apr 2026 15:09:31 +0800 Subject: [PATCH] =?UTF-8?q?fix(upload):=20=E5=88=86=E7=89=87=E6=94=B9=20PO?= =?UTF-8?q?ST=20=E5=B9=B6=E6=94=BE=E5=AE=BD=20Nginx=20=E5=8F=8D=E4=BB=A3?= =?UTF-8?q?=EF=BC=8C=E9=81=BF=E5=85=8D=20PUT=20=E5=A4=A7=20body=20?= =?UTF-8?q?=E6=96=AD=E8=BF=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 管理端分片请求改为 POST;后端同时保留 PUT - /api/ 增加 proxy_request_buffering off;CORS Allow-Headers 略扩展 Made-with: Cursor --- admin/src/api/admin.js | 2 +- nginx/nginx.conf | 1 + nginx/yuheng.docker.conf.tpl | 1 + nginx/yuheng.host.conf | 1 + server/handlers/multipart_upload.go | 2 +- server/main.go | 4 +++- 6 files changed, 8 insertions(+), 3 deletions(-) diff --git a/admin/src/api/admin.js b/admin/src/api/admin.js index f4f3995..6cc6eb2 100644 --- a/admin/src/api/admin.js +++ b/admin/src/api/admin.js @@ -104,7 +104,7 @@ export const getMultipartUploadStatus = (siteId, uploadId) => request.get(`/admin/sites/${siteId}/assets/multipart/${uploadId}/status`, { timeout: 60000 }) export const putMultipartChunk = (siteId, uploadId, chunkIndex, blob) => - request.put(`/admin/sites/${siteId}/assets/multipart/${uploadId}/chunk/${chunkIndex}`, blob, { + request.post(`/admin/sites/${siteId}/assets/multipart/${uploadId}/chunk/${chunkIndex}`, blob, { headers: { 'Content-Type': 'application/octet-stream' }, timeout: 180000 }) diff --git a/nginx/nginx.conf b/nginx/nginx.conf index f8e3789..96a8167 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -44,6 +44,7 @@ server { proxy_send_timeout 86400s; proxy_read_timeout 86400s; proxy_buffering off; + proxy_request_buffering off; } location /admin/ { diff --git a/nginx/yuheng.docker.conf.tpl b/nginx/yuheng.docker.conf.tpl index 2bd0429..140c972 100644 --- a/nginx/yuheng.docker.conf.tpl +++ b/nginx/yuheng.docker.conf.tpl @@ -76,6 +76,7 @@ server { proxy_send_timeout 86400s; proxy_read_timeout 86400s; proxy_buffering off; + proxy_request_buffering off; } # 尾斜杠形式:proxy_pass 带 / 会去掉 /admin 前缀,上游收到 /assets/…、/index.html 等 diff --git a/nginx/yuheng.host.conf b/nginx/yuheng.host.conf index a379584..09c95d9 100644 --- a/nginx/yuheng.host.conf +++ b/nginx/yuheng.host.conf @@ -82,6 +82,7 @@ server { proxy_send_timeout 86400s; proxy_read_timeout 86400s; proxy_buffering off; + proxy_request_buffering off; } location /admin/ { diff --git a/server/handlers/multipart_upload.go b/server/handlers/multipart_upload.go index ba96dce..beb9d62 100644 --- a/server/handlers/multipart_upload.go +++ b/server/handlers/multipart_upload.go @@ -215,7 +215,7 @@ func MultipartUploadStatus(c *gin.Context) { }) } -// PutMultipartChunk 上传单个分片(二进制 body,长度须与分片大小一致) +// PutMultipartChunk 上传单个分片(二进制 body,长度须与分片大小一致)。路由同时注册 POST 与 PUT,建议客户端用 POST。 func PutMultipartChunk(c *gin.Context) { siteID := c.Param("site_id") uploadID := c.Param("upload_id") diff --git a/server/main.go b/server/main.go index 9d6e8dc..26ac940 100644 --- a/server/main.go +++ b/server/main.go @@ -99,7 +99,7 @@ func main() { c.Header("Access-Control-Allow-Origin", "*") } c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") - c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization") + c.Header("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept, Origin, X-Requested-With") if c.Request.Method == "OPTIONS" { c.AbortWithStatus(http.StatusNoContent) return @@ -174,6 +174,8 @@ func main() { admin.POST("/sites/:site_id/assets", handlers.RequirePermission(models.PermModuleUpload), handlers.UploadSiteAsset) admin.POST("/sites/:site_id/assets/init-multipart", handlers.RequirePermission(models.PermModuleUpload), handlers.InitMultipartUpload) admin.GET("/sites/:site_id/assets/multipart/:upload_id/status", handlers.RequirePermission(models.PermModuleUpload), handlers.MultipartUploadStatus) + // 分片用 POST:部分反向代理对 PUT + 大 body 会断连,浏览器表现为 Network Error + admin.POST("/sites/:site_id/assets/multipart/:upload_id/chunk/:chunk_index", handlers.RequirePermission(models.PermModuleUpload), handlers.PutMultipartChunk) admin.PUT("/sites/:site_id/assets/multipart/:upload_id/chunk/:chunk_index", handlers.RequirePermission(models.PermModuleUpload), handlers.PutMultipartChunk) admin.POST("/sites/:site_id/assets/multipart/:upload_id/complete", handlers.RequirePermission(models.PermModuleUpload), handlers.CompleteMultipartUpload) admin.DELETE("/sites/:site_id/assets/multipart/:upload_id", handlers.RequirePermission(models.PermModuleUpload), handlers.AbortMultipartUpload)