Solution of CURL parsing timeout

Keywords: PHP curl SDK network

Background: In a project, it is necessary to upload CRM images to OSS and call OssClient.php, which is prone to parse timeouts (ok if you try several times).

Error prompt:

[2019-04-08 19:41:01] lumen.DEBUG: Error file:/home/zrj/www/admin/yundou-admin/vendor/aliyuncs/oss-sdk-php/src/OSS/OssClient.php  
[2019-04-08 19:41:01] lumen.DEBUG: Error Coding:0  
[2019-04-08 19:41:01] lumen.DEBUG: Error line number: 2187  
[2019-04-08 19:41:01] lumen.DEBUG: Error message: RequestCoreException: cURL resource: Resource id #371; cURL error: Resolving timed out after 10521 milliseconds (28) 

Resolving timed out after 10521 milliseconds (28)
Analytical timeout

Source code analysis:

try {
            $ossClient = new OssClient(self::$accessKeyId, self::$accessKeySecret, self::$endpoint);
            $ossClient->uploadFile(self::$bucket, $ossFileName, $localhostFileName);//Upload files
            $ossClient->putBucketAcl(self::$bucket, OssClient::OSS_ACL_TYPE_PUBLIC_READ);
        } catch (OssException $e) {
            self::debugException($e);
            throw new \Exception("upload oss fail:" . $e->getMessage(), $e->getCode());
        }

1. After the OssClient client is instantiated, the uploadFile method is called.
2.uploadFile calls auth, validates and executes requests, and executes operations in accordance with the OSS Api protocol.

    /**
     * Upload local files
     *
     * @param string $bucket bucket Name
     * @param string $object object Name
     * @param string $file Local file path
     * @param array $options
     * @return null
     * @throws OssException
     */
    public function uploadFile($bucket, $object, $file, $options = NULL)
    {
        ......
        $response = $this->auth($options);
        $result = new PutSetDeleteResult($response);
        return $result->getData();
    }

3. Call the RequestCore class to create the request in auth

    /**
     * Verify and execute requests, perform operations according to OSS Api protocol
     *
     * @param array $options
     * @return ResponseCore
     * @throws OssException
     * @throws RequestCore_Exception
     */
    private function auth($options)
    {
            ......
        //Create request
        $request = new RequestCore($this->requestUrl, $this->requestProxy);
        $request->set_useragent($this->generateUserAgent());
                ......
                try {
            $request->send_request();
        } catch (RequestCore_Exception $e) {
            throw(new OssException('RequestCoreException: ' . $e->getMessage()));
        }
    }

4. The send_request method in the OSS Http RequestCore class sends requests through CURL (calling the prep_request preparation request method)

 /**
     * Sends the request, calling necessary utility functions to update built-in properties.
     *
     * @param boolean $parse (Optional) Whether to parse the response with ResponseCore or not.
     * @return string The resulting unparsed data from the request.
     */
    public function send_request($parse = false)
    {
        set_time_limit(0);

        $curl_handle = $this->prep_request();
        $this->response = curl_exec($curl_handle);

        if ($this->response === false) {
            throw new RequestCore_Exception('cURL resource: ' . (string)$curl_handle . '; cURL error: ' . curl_error($curl_handle) . ' (' . curl_errno($curl_handle) . ')');
        }

        $parsed_response = $this->process_response($curl_handle, $this->response);

        curl_close($curl_handle);

        if ($parse) {
            return $parsed_response;
        }

        return $this->response;
    }

5. Finally, the CURL in RequestCore can be deduced.

Solution:
curl has a CURLOPT_IPRESOLVE option to specify which IP protocol to use (IPV4/IPV6).

CURLOPT_IPRESOLVE - specify which IP protocol version to use

Options:
CURL_IPRESOLVE_WHATEVER

Default, resolves addresses to all IP versions that your system allows.

CURL_IPRESOLVE_V4

Resolve to IPv4 addresses.

CURL_IPRESOLVE_V6

Resolve to IPv6 addresses.

Note here: The default value (when curl does not actively set the CURLOPT_IPRESOLVE option, the system will use the default value).

Default, resolves addresses to all IP versions that your system allows.

Meaning: By default, all IP versions allowed by the server system are used to resolve addresses.
The server system may support IPV4/IPV6 at the same time, and CURL will try one by one. Timeout occurs when the local network does not support any of these IP version protocols.

So the final solution is to explicitly specify the CURL CLULPT_IPRESOLVE option.

curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);

Reference resources Official CURLOPT_IPRESOLVE

Posted by nrg_alpha on Mon, 08 Apr 2019 16:09:31 -0700