Curl POST被执行成了GET请求

4
我正在尝试使用PHP开发一种浏览器。到目前为止,我的类可以处理GET或POST请求,并且可以处理以下Content Type: application/x-www-form-urlencoded。
现在我需要转移到JSON类型。我已将Content-Type标头设置为application/json。事实是,使用此类型会出现以下问题:设置POST请求将导致GET请求。这真的很奇怪。
以下是我的代码:
private function request($url, $reset_cookies, $post_data = null, $custom_headers = null)
{       
    // Create options
    $options = array(
        CURLOPT_URL               => $url,
        CURLOPT_RETURNTRANSFER    => 1,
        CURLOPT_HEADER            => 0,
        CURLINFO_HEADER_OUT       => 1,
        CURLOPT_FAILONERROR       => 1,
        CURLOPT_USERAGENT         => $this->user_agent,
        CURLOPT_CONNECTTIMEOUT    => 30,
        CURLOPT_TIMEOUT           => 30,
        CURLOPT_FOLLOWLOCATION    => 1,
        CURLOPT_MAXREDIRS         => 10,
        CURLOPT_AUTOREFERER       => 1,
        CURLOPT_COOKIESESSION     => $reset_cookies ? 1 : 0,
        CURLOPT_COOKIEJAR         => $this->cookies_file,
        CURLOPT_COOKIEFILE        => $this->cookies_file,
        CURLOPT_HTTPHEADER        => array('Accept-language: en'),

        // SSL
        /*
        CURLOPT_SSL_CIPHER_LIST   => 'TLSv1',
        CURLOPT_SSL_VERIFYPEER    => 1,
        CURLOPT_CAINFO            => dirname(__FILE__) . '/Entrust.netCertificationAuthority(2048).crt',
        */
    );

    // Add headers
    if (isset($custom_headers)) $options[CURLOPT_HTTPHEADER] = array_merge($options[CURLOPT_HTTPHEADER], $custom_headers);

    // Add POST data
    if (isset($post_data))
    {
        $options[CURLOPT_POST]          = 1;
        $options[CURLOPT_POSTFIELDS]    = is_string($post_data) ? $post_data : http_build_query($post_data);
    }

    // Attach options
    curl_setopt_array($this->curl, $options);

    // Execute the request and read the response
    $content = curl_exec($this->curl);

    print_r($options);
    print_r(curl_getinfo($this->curl, CURLINFO_HEADER_OUT));

    // Clean local variables
    unset($url);
    unset($reset_cookies);
    unset($post_data);
    unset($custom_headers);
    unset($options);

    // Handle any error
    if (curl_errno($this->curl))
    {
        unset($content);
        throw new Exception(curl_error($this->curl));
    }

    return $content;
}

为了阐明我的问题,这里有一个例子:
CUrl选项作为Array
Array
(
    [10002] => http://mywebsite.com/post/
    [19913] => 1
    [42] => 0
    [2] => 1
    [45] => 1
    [10018] => Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
    [78] => 30
    [13] => 30
    [52] => 1
    [68] => 10
    [58] => 1
    [96] => 0
    [10082] => C:\wamp\www\v2\_libs/../_cookies/14d0fd2b-9f15-4ac5-8fae-4246cc6cef49.cookie
    [10031] => C:\wamp\www\v2\_libs/../_cookies/14d0fd2b-9f15-4ac5-8fae-4246cc6cef49.cookie
    [10023] => Array
        (
            [0] => Accept-language: en
            [1] => RequestVerificationToken: 4PMxvJsQzFJ5oFt3JdUPe6Bp_geIj4obDJCYIRoU09PrrfcBSUgJT9iB3mXnGFc2KSlYrPcRHF7iHdQhGNu0GKLUzd5FywfaADbGS8wjhXraF36W0
            [2] => Content-Type: application/json
        )

    [47] => 1
    [10015] => {"usernameOrFeedId":"manitoba","feed_message_body":"Dummy message goes here"}
)

这个请求头看起来对我来说很好,但我可能错了。

这是由CUrl发送的真实头部:

GET /post/ HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
Host: mywebsite.com
Accept: */*
Referer: http://mywebsite.com/post/
Cookie: ADRUM_BT=R%3a53%7cclientRequestGUID%3a9787a51b-b24d-4400-9d6a-efbd618c74c0%7cbtId%3a18790%7cbtERT%3a44; CSRFToken=o_eoIVji7pWclOsrLaJpZEbOFSBJBm851rHbH0Xqwdzw2tC5j07EAc23mlj-opWowgpj0RkHyiktl1cS6onBqI43afM1; WebSessionId=3aem0m2xpwmvesgphna5gaop; prod=rd101o00000000000000000000ffff0a5a2a74o80; AuthenticateCookie=AAAAAtsQgeb8+UXrJ+wa7CGVJKnqizEAo2bMuFvqvwYMAl1NRaa6z68LBRx9hiHzPBC8tYqiayHID6pHChGXB7VywemwTpGivcRQ3nRlUVuaYQKyxQt21p1mx7OMlLCsRA==; web_lang.prod=fr
Accept-language: en
RequestVerificationToken: 4PMxvJsQzFJ5oFt3JdUPe6Bp_geIj4obDJCYIRoU09PrrfcBSUgJT9iB3mXnGFc2KSlYrPcRHF7iHdQhGNu0GKLUzd5FywfaADbGS8wjhXraF34W0
Content-Type: application/json

正如您所看到的,这是一次GET请求,而提交的数据好像已经消失了。

我做错了什么吗?

3个回答

6
您正在跟随重定向,这意味着您会收到一个3xx响应代码,curl会向新的URL发出第二个请求。
对于一些重定向,curl会根据特定的3xx代码采取不同的行动,并且它会将请求方法从POST更改为GET - 启用VERBOSE将显示它是否这样做。使curl更改方法的响应代码是301、302和303。这样做是因为浏览器在这些响应代码上的操作方式。 libcurl提供了一个称为CURLOPT_POSTREDIR的选项,您可以使用它告诉curl对于特定的HTTP响应不要更改方法。使用它,您可以让curl在使用这些响应代码之一重定向后仍发送POST。

1

你好@Exussum,我确认服务器正在执行PRG。我该如何解决?由于不是我的服务器,也无法访问其代码,因此我无法编辑服务器代码。 - Manitoba
服务器将始终回复一个新位置,您可以选择不遵循它。帖子已经发生了两种方式。第二种方式,最后一个操作(以及curl报告的操作)是GET。但POST也确实发生了。 - exussum

1

通过将其设置为false并从代码中删除curlopt_maxredirs来禁用跟随位置。

    CURLOPT_FOLLOWLOCATION    => false,
    // CURLOPT_MAXREDIRS         => 10,

嗨,谢谢你的回答。问题是,由于服务器上有重定向(而且不是我的服务器,我无法编辑代码),所以我无法删除此设置。 - Manitoba

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接