我使用workman并开启了协程,限制只有1个进程运行,我有一个client类,并使用单例模式来实现全局只有一个请求类,代码如下,我发现当我用浏览器请求这个接口,要是一个接口请求完后再请求接口的方式,每次请求这个接口都可以返回数据,但要是我并发请求这个接口,就会报错Value of type null is not callable,有没有大佬解释一下呢?
<?php
###client类
namespace diyvendor;
use React;
use React\Async;
use React\Http\Browser;//版本1.1
use React\Socket\Connector;
use React\EventLoop\Loop;
use diyvendor\logger\Log;
class client{
private static $instance;
protected $timeout=30000;//// in milliseconds
protected $browser;
protected $headers=array();
protected $quoteJsonNumbers=true;
protected $userAgents = array(
'chrome' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36',
'chrome39' => 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36',
'chrome100' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36',
);//暂时用不上
private function __construct(){
$this->browser=self::setBrowser(array(),$this->timeout);
}
public static function getInstance(){
if(isset(self::$instance) && !empty(self::$instance)){
return self::$instance;
}else{
return self::$instance=new self();
}
}
private static function setBrowser($connector_options=array(),$timeout=1000){
$connector = new Connector(array_merge(array(
'timeout' => $timeout,
), $connector_options), Loop::get());
return (new Browser($connector, Loop::get()))->withRejectErrorResponse(false);
}
//该方法会返回$http_status_code, $http_status_text, $url, $method, $response_headers, $response_body, $json_response, $headers, $body
public function fetch($url='',$method='GET',$headers=null,$body=null,$rand=''){
return React\Async\async(function () use ($url, $method, $headers, $body,$rand) {
$headers = array_merge($this->headers, $headers ? $headers : array());
try {
$body = $body ?? '';
$result = React\Async\await($this->browser->request($method, $url, $headers, $body));
}catch (\Exception $e) {
$message = $e->getMessage();
if (strpos($message, 'timed out') !== false) {
//timeOut
throw new \Exception(implode(' ', array($url, $method, 28, $message)));
}else if (strpos($message, 'DNS query') !== false) {
throw new \Exception($message);
} else {
throw new \Exception($message);
}
}
$raw_response_headers = $result->getHeaders();//响应头部=-原始数据
$raw_header_keys = array_keys($raw_response_headers);//响应头部--原始数据--key
$response_headers = array();//响应头部--处理后的数据--key--value
foreach ($raw_header_keys as $header) {
$response_headers[$header] = $result->getHeaderLine($header);
}
$http_status_code = $result->getStatusCode();//code
$http_status_text = $result->getReasonPhrase();
$response_body = strval($result->getBody());
$response_body = $this->_on_rest_response($http_status_code, $http_status_text, $url, $method, $response_headers, $response_body, $headers, $body);
$json_response = null;
$is_json_encoded_response = $this->_is_json_encoded_object($response_body);
if ($is_json_encoded_response) {
$json_response = $this->_parse_json($response_body);
}
//上面就是对下面的参数进行提取
return [
'request_url'=>$url,
'request_method'=>$method,
'request_body'=>$body,
'request_headers'=>$headers,
'response_result'=>isset($json_response)?$json_response : $response_body,
'response_headers'=>$response_headers,
'response_code'=>$http_status_code,
'response_text'=>$http_status_text,
];
}) ();
}
private function _parse_json($json_string, $as_associative_array = true){
return json_decode($this->_on_json_response($json_string), $as_associative_array);
}
private function _on_json_response($response_body) {
return (is_string($response_body) && $this->quoteJsonNumbers) ? preg_replace('/":([+.0-9eE-]+)([,}])/', '":"$1"$2', $response_body) : $response_body;
}
private function _is_json_encoded_object($input){
return ('string' === gettype($input)) &&
(strlen($input) >= 2) &&
(('{' === $input[0]) || ('[' === $input[0]));
}
private function _on_rest_response($code, $reason, $url, $method, $response_headers, $response_body, $request_headers, $request_body){
return is_string($response_body) ? trim($response_body) : $response_body;
}
}
?>
use diyvendor\client;
#....某个方法
$client=client::getInstance();
$promisesRaw=array();
$promisesRaw[]=$client->fetch('http://www.baidu.com');
$promisesRaw[]=$client->fetch('http://www.baidu.com');
$promisesRaw[]=$client->fetch('http://www.baidu.com');
$promises =React\Async\await(Promise\all($promisesRaw));
return $this->success('获取成功',$promises);
协程下最好不要再异步请求
我的接口处理所需时间比较长(处理过程对外请求次数好几次,每次请求快则几百毫秒,慢则超5秒),开启协程,就是可以提高并发请求进来的处理能力,我使用异步请求是想缩短对外请求好几次所带来的时间过程问题