|
1 | 1 | package handler |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "bytes" |
4 | 5 | "fmt" |
5 | 6 | "io" |
6 | 7 | "net/http" |
7 | 8 | "path/filepath" |
| 9 | + "strings" |
8 | 10 |
|
9 | 11 | "github.com/mdfriday/hugoverse/internal/application" |
10 | 12 | "github.com/mdfriday/hugoverse/internal/infrastructure/github" |
@@ -58,11 +60,61 @@ func (s *Handler) GithubReleaseHander(res http.ResponseWriter, req *http.Request |
58 | 60 | } |
59 | 61 |
|
60 | 62 | // 解析 payload |
61 | | - // GitHub webhook 直接在 request body 中发送 JSON(即使 Content-Type 是 application/x-www-form-urlencoded) |
62 | | - payload, err := github.ParseReleasePayload(body) |
| 63 | + // 根据 GitHub 官方文档: https://docs.github.com/zh/webhooks/webhook-events-and-payloads |
| 64 | + // GitHub Webhook 支持两种 Content-Type: |
| 65 | + // 1. application/json: JSON 直接在 body 中(推荐) |
| 66 | + // 2. application/x-www-form-urlencoded: JSON 在表单字段 "payload" 中 |
| 67 | + var payloadData []byte |
| 68 | + contentType := req.Header.Get("Content-Type") |
| 69 | + |
| 70 | + s.log.Infof("Webhook received - Content-Type: %s, Body length: %d", contentType, len(body)) |
| 71 | + |
| 72 | + if strings.Contains(contentType, "application/json") { |
| 73 | + // 格式 1: JSON 直接在 body 中 |
| 74 | + s.log.Infof("Parsing as application/json") |
| 75 | + payloadData = body |
| 76 | + } else if strings.Contains(contentType, "application/x-www-form-urlencoded") { |
| 77 | + // 格式 2: JSON 在表单字段 "payload" 中 |
| 78 | + s.log.Infof("Parsing as application/x-www-form-urlencoded") |
| 79 | + |
| 80 | + // 需要重新包装 body 供 ParseForm 使用 |
| 81 | + req.Body = io.NopCloser(bytes.NewBuffer(body)) |
| 82 | + if err := req.ParseForm(); err != nil { |
| 83 | + s.log.Errorf("Failed to parse form: %v", err) |
| 84 | + res.WriteHeader(http.StatusBadRequest) |
| 85 | + fmt.Fprintf(res, "Failed to parse form data") |
| 86 | + return |
| 87 | + } |
| 88 | + |
| 89 | + payloadStr := req.FormValue("payload") |
| 90 | + if payloadStr == "" { |
| 91 | + s.log.Errorf("Missing 'payload' field in form data") |
| 92 | + res.WriteHeader(http.StatusBadRequest) |
| 93 | + fmt.Fprintf(res, "Missing 'payload' field in form data") |
| 94 | + return |
| 95 | + } |
| 96 | + |
| 97 | + payloadData = []byte(payloadStr) |
| 98 | + s.log.Infof("Extracted payload from form field (length: %d)", len(payloadData)) |
| 99 | + } else { |
| 100 | + s.log.Errorf("Unsupported Content-Type: %s", contentType) |
| 101 | + res.WriteHeader(http.StatusBadRequest) |
| 102 | + fmt.Fprintf(res, "Unsupported Content-Type: %s", contentType) |
| 103 | + return |
| 104 | + } |
| 105 | + |
| 106 | + s.log.Infof("Parsing JSON payload (length: %d)", len(payloadData)) |
| 107 | + payload, err := github.ParseReleasePayload(payloadData) |
63 | 108 | if err != nil { |
64 | 109 | s.log.Errorf("Failed to parse release payload: %v", err) |
| 110 | + // 显示前 500 个字符用于调试 |
| 111 | + maxLen := 500 |
| 112 | + if len(payloadData) < maxLen { |
| 113 | + maxLen = len(payloadData) |
| 114 | + } |
| 115 | + s.log.Errorf("Payload data (first %d chars): %s", maxLen, string(payloadData[:maxLen])) |
65 | 116 | res.WriteHeader(http.StatusBadRequest) |
| 117 | + fmt.Fprintf(res, "Failed to parse payload: %v", err) |
66 | 118 | return |
67 | 119 | } |
68 | 120 |
|
|
0 commit comments