PHP Curl - 跟随“201 Created”响应头的位置

I am submitting a CURL Post request to an API which, upon success, returns status "201 Created" with the URL of the resource in the LOCATION part of the header. What I'd like is to automatically retrieve the newly created resource but so far haven't been able to do so. I've tried setting curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); but to no avail. it's worth noting that the resource does require a GET request.

I'm not sure if it's the status code being a 201, or if the request method needs to change from POST to GET, but for some reason it's not following the LOCATION header. Fetching curl_getinfo($ch,CURLINFO_EFFECTIVE_URL); seems to confirm this as the result is the same as the original URL, not the new LOCATION.

As a last resort I have considered simply parsing the headers and creating a new CURL request, but this would not be optimal and I'm guessing that I'm just missing something simple to make this work as desired.

How can I get CURL to automatically follow and submit a GET request to the LOCATION returned with a 201 response?

You can't.

With curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl follow the response LOCATION only for 3xx status codes.

AFAIK and stating as the documentation there is no way to force curl to follow-location with a 201 response.

You have to parse the header, fetch the LOCATION and then issue a second curl request.

Following a location with a status different than 3xx would be an anomaly. Also from the curl command line tool and C library documentation: -L, --location -- (HTTP) If the server reports that the requested page has moved to a different location (indicated with a Location: header and a 3XX response code), this option will make curl redo the request on the new place


Giving a quick look at the curl source code you find on /lib/http.c the function Curl_http_readwrite_headers.

Location follow is handled inside with this conditional:

else if((k->httpcode >= 300 && k->httpcode < 400) &&
        checkprefix("Location:", k->p) &&
        !data->req.location) {
  /* this is the URL that the server advises us to use instead */
  char *location = Curl_copy_header_value(k->p);
  if(!location)
    return CURLE_OUT_OF_MEMORY;
  if(!*location)
    /* ignore empty data */
    free(location);
  else {
    data->req.location = location;

    if(data->set.http_follow_location) {
      DEBUGASSERT(!data->req.newurl);
      data->req.newurl = strdup(data->req.location); /* clone */
      if(!data->req.newurl)
        return CURLE_OUT_OF_MEMORY;

      /* some cases of POST and PUT etc needs to rewind the data
         stream at this point */
      result = http_perhapsrewind(conn);
      if(result)
        return result;
    }
  }
}

The location is followed with a status code between 300 and 399

I understand this doesn't answer your question in the pure sense of it -- my solution isn't even in PHP, but here's a way (using jq) to follow a 201 with cURL:

shrinkImageFunction() {
 echo
 echo Compressing $1 . . .

 curl --user api: https://tinypng.com/developers \
      --data-binary @$1 \
      -o .$1-json \
      -s \
      https://api.tinify.com/shrink

 cat .$1-json | jq -r '.output.url' > .$1-url

 url=$(cat .$1-url)

 if [ -z "$url" ]; then
      echo Something went wrong
      return
 fi

 echo Downloading $url . . .

 echo
 curl -o compressed-$1 $url
 echo

 rm .$1-json
 rm .$1-url
}

# alias for using tinypng
alias shrinkImage=shrinkImageFunction

I threw this together today while doing similar research and figured I'd share having come across this question while looking for options.

It could easily be tweaked to parse the http 201 header response using sed or similar instead of jq where I'm parsing the http body json response provided by tinypng (used merely for reference -- I'm not affiliated with them).