data(CryptoLogic::market()); } catch (\Throwable $e) { Log::error('[CryptoMarket] controller failed: ' . $e->getMessage()); return $this->fail('行情加载失败,请稍后重试'); } } /** * 当前账号的加密自选列表 */ public function favorites() { if ($this->userId <= 0) { return $this->fail('请先登录', [], 401); } return $this->data(['symbols' => CryptoLogic::favorites($this->userId)]); } /** * 加入加密自选 */ public function addFavorite() { if ($this->userId <= 0) { return $this->fail('请先登录', [], 401); } $params = (new CryptoValidate())->post()->goCheck('favorite'); if (!CryptoLogic::addFavorite($this->userId, (string) $params['symbol'])) { return $this->fail(CryptoLogic::getError()); } return $this->success('已加入自选'); } /** * 取消加密自选 */ public function cancelFavorite() { if ($this->userId <= 0) { return $this->fail('请先登录', [], 401); } $params = (new CryptoValidate())->post()->goCheck('favorite'); if (!CryptoLogic::cancelFavorite($this->userId, (string) $params['symbol'])) { return $this->fail(CryptoLogic::getError()); } return $this->success('已取消自选'); } /** * Binance API 代理(解决客户端直连被墙问题) * GET /api/crypto/proxy?path=/api/v3/ticker/24hr&symbols=... */ public function proxy() { $path = $this->request->get('path', ''); if (empty($path) || !str_starts_with($path, '/api/v3/')) { return $this->fail('无效的API路径'); } // 构建完整URL,将除 path 外的参数透传 $params = $this->request->get(); unset($params['path']); ksort($params); $query = http_build_query($params); $url = 'https://api.binance.com' . $path . ($query ? '?' . $query : ''); $cacheKey = 'binance_proxy_' . md5($path . '|' . $query); $cached = Cache::get($cacheKey); if ($cached !== null) { return json($cached, 200); } Log::info('[CryptoProxy] request url=' . $url); $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 15, CURLOPT_CONNECTTIMEOUT => 5, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_HTTPHEADER => ['Accept: application/json'], ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if ($error) { Log::error('[CryptoProxy] curl_error=' . $error . ' url=' . $url); return $this->fail('API请求失败: ' . $error); } Log::info('[CryptoProxy] http_code=' . $httpCode . ' response_preview=' . substr((string) $response, 0, 500)); $data = json_decode($response, true); if ($httpCode === 200 && $data !== null) { Cache::set($cacheKey, $data, 3); } return json($data, $httpCode); } }