package service import ( "context" "fmt" "io" "net/http" "net/url" "strings" "time" "model-asynch/model/entity" "github.com/gogf/gf/v2/frame/g" ) // triggerSuccessCallback 任务成功后的回调钩子: // - 使用 GET 请求 // - 回调地址为 callbackUrl + "/" + bizName // - query 参数:task_id/state/oss_file/file_type // 注意:回调失败不影响任务主流程,只记录日志。 func triggerSuccessCallback(ctx context.Context, t *entity.AsynchTask) { if t == nil { return } callbackURL := strings.TrimSpace(t.CallbackURL) bizName := strings.TrimSpace(t.BizName) if callbackURL == "" || bizName == "" { return } u, err := url.Parse(callbackURL) if err != nil { g.Log().Warningf(ctx, "[callback] invalid callbackUrl=%s err=%v", callbackURL, err) return } // 必须是可发起 HTTP 请求的绝对地址 if u.Scheme == "" || u.Host == "" { g.Log().Warningf(ctx, "[callback] callbackUrl must be absolute http(s) url, got=%s", callbackURL) return } // path 末尾拼接 bizName bizSeg := url.PathEscape(bizName) if strings.HasSuffix(u.Path, "/") || u.Path == "" { u.Path = strings.TrimRight(u.Path, "/") + "/" + bizSeg } else { u.Path = u.Path + "/" + bizSeg } q := u.Query() q.Set("task_id", t.TaskID) q.Set("state", fmt.Sprintf("%d", t.State)) q.Set("oss_file", t.OssFile) q.Set("file_type", t.FileType) u.RawQuery = q.Encode() req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil) if err != nil { g.Log().Warningf(ctx, "[callback] build request failed url=%s err=%v", u.String(), err) return } // 透传必要头部(如 Authorization / X-User-Info) for k, v := range forwardHeaders(ctx) { if v != "" { req.Header.Set(k, v) } } client := &http.Client{Timeout: 5 * time.Second} resp, err := client.Do(req) if err != nil { g.Log().Warningf(ctx, "[callback] request failed url=%s err=%v", u.String(), err) return } defer resp.Body.Close() b, _ := io.ReadAll(resp.Body) if resp.StatusCode < 200 || resp.StatusCode >= 300 { msg := string(b) if len(msg) > 2000 { msg = msg[:2000] } g.Log().Warningf(ctx, "[callback] non-2xx url=%s code=%d body=%s", u.String(), resp.StatusCode, msg) return } g.Log().Infof(ctx, "[callback] success url=%s code=%d", u.String(), resp.StatusCode) }