/** * 执行外部请求,并返回接口 * * $request->execute(); * * @param Request $request * @param Response $response * @return Response * @throws Exception */ public function executeRequest(Request $request, Response $response) { $previous = Request::$current; Request::$current = $request; // 如果post数据了 if ($post = $request->post()) { $request->body = http_build_query($post, null, '&'); $request->headers('content-type', 'application/x-www-form-urlencoded; charset=' . $request->charset); } // 如果需要暴露框架信息 if (Base::$expose) { $request->headers('user-agent', Base::version()); } try { // 处理header $sendHeaders = []; if ($headers = $request->headers()) { foreach ($headers as $key => $value) { if (is_array($value)) { $value = implode(', ', $value); } $sendHeaders[$key] = $value; } } // 处理cookie if ($cookies = $request->cookie()) { $sendHeaders['Cookie'] = http_build_query($cookies, null, '; '); } $url = $request->uri; if ($query = $request->query()) { $url .= '?' . http_build_query($query, null, '&'); } // 执行请求 $result = Requests::request($url, $sendHeaders, $request->body, $request->method, $this->options); if (!$result->success) { throw new RequestException('Error fetching remote :url [ status :code ]', [':url' => $url, ':code' => $result->status_code]); } foreach ($result->headers as $k => $v) { $response->headers($k, $v); } $response->status = $result->status_code; $response->body = $result->body; } catch (Exception $e) { Request::$current = $previous; throw $e; } Request::$current = $previous; return $response; }
/** * 渲染当前响应对象 * * @return string */ public function render() { Base::getLog()->debug(__METHOD__ . ' render response object'); if (!$this->headers('content-type')) { $this->headers('content-type', Base::$contentType . '; charset=' . $this->charset); } $this->headers('content-length', (string) $this->contentLength); if (Base::$expose) { $this->headers('user-agent', Base::version()); } if ($this->cookies) { if (extension_loaded('http')) { $this->headers('set-cookie', http_build_cookie($this->cookies)); } else { $cookies = []; foreach ($this->cookies as $key => $value) { $string = $key . '=' . $value['value'] . '; expires=' . date('l, d M Y H:i:s T', $value['expiration']); $cookies[] = $string; } $this->headers('set-cookie', $cookies); } } $output = $this->protocol . ' ' . $this->status . ' ' . Arr::get(Http::$text, $this->status) . "\r\n"; $output .= $this->message->headerLines; $output .= $this->message->body; return $output; }
/** * 将当前进程的统计信息写入到统计文件 * * @return void */ protected static function writeStatisticsToStatusFile() { // 主进程部分 if (self::$_masterPid === posix_getpid()) { $loadAvg = sys_getloadavg(); file_put_contents(self::$statusFile, "---------------------------------------GLOBAL STATUS--------------------------------------------\n"); file_put_contents(self::$statusFile, 'Tourze version:' . Base::version() . " PHP version:" . PHP_VERSION . "\n", FILE_APPEND); file_put_contents(self::$statusFile, 'start time:' . date('Y-m-d H:i:s', self::$_globalStatistics['start_timestamp']) . ' run ' . floor((time() - self::$_globalStatistics['start_timestamp']) / (24 * 60 * 60)) . ' days ' . floor((time() - self::$_globalStatistics['start_timestamp']) % (24 * 60 * 60) / (60 * 60)) . " hours \n", FILE_APPEND); file_put_contents(self::$statusFile, 'load average: ' . implode(", ", $loadAvg) . "\n", FILE_APPEND); file_put_contents(self::$statusFile, count(self::$_pidMap) . ' workers ' . count(self::getAllWorkerPids()) . " processes\n", FILE_APPEND); file_put_contents(self::$statusFile, str_pad('worker_name', self::$_maxWorkerNameLength) . " exit_status exit_count\n", FILE_APPEND); foreach (self::$_pidMap as $worker_id => $worker_pid_array) { $worker = self::$_workers[$worker_id]; if (isset(self::$_globalStatistics['worker_exit_info'][$worker_id])) { foreach (self::$_globalStatistics['worker_exit_info'][$worker_id] as $worker_exit_status => $worker_exit_count) { file_put_contents(self::$statusFile, str_pad($worker->name, self::$_maxWorkerNameLength) . " " . str_pad($worker_exit_status, 16) . " {$worker_exit_count}\n", FILE_APPEND); } } else { file_put_contents(self::$statusFile, str_pad($worker->name, self::$_maxWorkerNameLength) . " " . str_pad(0, 16) . " 0\n", FILE_APPEND); } } file_put_contents(self::$statusFile, "---------------------------------------PROCESS STATUS-------------------------------------------\n", FILE_APPEND); file_put_contents(self::$statusFile, "pid\tmemory " . str_pad('listening', self::$_maxSocketNameLength) . " " . str_pad('worker_name', self::$_maxWorkerNameLength) . " connections " . str_pad('total_request', 13) . " " . str_pad('send_fail', 9) . " " . str_pad('throw_exception', 15) . "\n", FILE_APPEND); chmod(self::$statusFile, 0722); foreach (self::getAllWorkerPids() as $worker_pid) { posix_kill($worker_pid, SIGUSR2); } return; } // 子进程部分 $worker = current(self::$_workers); $statusStr = posix_getpid() . "\t" . str_pad(round(memory_get_usage(true) / (1024 * 1024), 2) . "M", 7) . " " . str_pad($worker->getSocketName(), self::$_maxSocketNameLength) . " " . str_pad($worker->name === $worker->getSocketName() ? 'none' : $worker->name, self::$_maxWorkerNameLength) . " "; $statusStr .= str_pad(ConnectionInterface::$statistics['connection_count'], 11) . " " . str_pad(ConnectionInterface::$statistics['total_request'], 14) . " " . str_pad(ConnectionInterface::$statistics['send_fail'], 9) . " " . str_pad(ConnectionInterface::$statistics['throw_exception'], 15) . "\n"; file_put_contents(self::$statusFile, $statusStr, FILE_APPEND); }
/** * 渲染请求,保存:协议、头部、内容主体 * * @return string */ public function render() { if (!($post = $this->post())) { $body = $this->body; } else { $this->headers('content-type', 'application/x-www-form-urlencoded; charset=' . $this->charset); $body = http_build_query($post, null, '&'); } $this->headers('content-length', (string) $this->contentLength); if (Base::$expose) { $this->headers('user-agent', Base::version()); } if ($this->_cookies) { $cookieString = []; // Parse each foreach ($this->_cookies as $key => $value) { $cookieString[] = $key . '=' . $value; } // 创建cookie字符串 $this->headers('cookie', implode('; ', $cookieString)); } $output = $this->method . ' ' . $this->uri . ' ' . $this->protocol . "\r\n"; $output .= $this->message->headerLines; $output .= $body; return $output; }