如何在Google App Engine中发送外部HTTP请求

I have a problem on issuing HTTP requests in appengine since it does not support http.Client. I'm creating a slackbot and want to create a delayed response. The logic is once I received slack's POST request, I'm going to respond successfully and spin a goroutine calling an external API and after I finish with it, create a new request to slack.

Seems easy enough, but the problem I encountered is when using appengine's urlfetch and NewContext, because NewContext takes in an *http.Request as an argument but since I'm responding immediately to the first slack request, the response Body closes before I can use it to issue the response to an external API. Is there an alternative?

code:

func Twit(w http.ResponseWriter, r *http.Request) {
    defaultResponse := &SlashResponse{ResponseType: "ephemeral", Text: "success"}

    // prepare to make a slack delayed response
    responseURL := r.FormValue("response_url")
    go sendDelayResponse(responseURL, r)

    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(200)
    json.NewEncoder(w).Encode(defaultResponse)
}

func sendDelayResponse(url string, r *http.Request) {
    response := &SlashResponse{ResponseType: "in_channel", Text: twit.TweetTCL(r)}
    b, _ := json.Marshal(response)

    // send request to slack using given response_url
    ctx := appengine.NewContext(r)
    client := urlfetch.Client(ctx)
    req, _ := http.NewRequest("POST", url, bytes.NewBuffer(b))
    req.Header.Add("Content-Type", "application/json")
    resp, err := client.Do(req)
    defer resp.Body.Close()

    if err != nil {
        log.Println(err)
    } else {
        log.Println("success")
    }
}

Use the delay package to execute functions outside the scope of a request.

You can also use the lower-level taskqueue package. The delay package is layer above the taskqueue package.

Declare package level variable with the delay function:

var laterFunc("dr", func(ctx context.Context, url string) {
  response := &SlashResponse{ResponseType: "in_channel", Text: twit.TweetTCL(r)}
  b, _ := json.Marshal(response)

  // send request to slack using given response_url
  client := urlfetch.Client(ctx)
  req, _ := http.NewRequest("POST", url, bytes.NewBuffer(b))
  req.Header.Add("Content-Type", "application/json")
  resp, err := client.Do(req)
  defer resp.Body.Close()

  if err != nil {
    log.Println(err)
  } else {
    log.Println("success")
  }
})

Call it like this:

laterfunc.Call(appengine.NewContext(r), responseURL)