import { Hono } from 'hono' import { serve } from '@hono/node-server' import { serveStatic } from '@hono/node-server/serve-static' import { chromium, type Browser, type BrowserContext, type Route, type Page } from 'playwright' import process from 'process' import fs from 'fs' const app = new Hono() // 浏览器实例 let browser: Browser | null = null let gensparkContext: BrowserContext | null = null // 为genspark保存的page实例 let gensparkPage: Page | null = null const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'; // 初始化浏览器 async function initBrowser() { if (!browser) { browser = await chromium.launch({ headless: true, args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', ], executablePath: process.env.PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH, // 使用系统 Chromium }) } return browser } // 初始化genspark页面 async function initGensparkPage(cookies?: any[]) { const browser = await initBrowser() if (!gensparkContext) { gensparkContext = await browser.newContext({ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', viewport: { width: 1920, height: 1080 }, deviceScaleFactor: 1, hasTouch: false, locale: 'en-US', timezoneId: 'America/New_York', geolocation: { longitude: -73.935242, latitude: 40.730610 }, // 纽约坐标,可根据需要调整 permissions: ['geolocation'], javaScriptEnabled: true, bypassCSP: true, // 绕过内容安全策略 colorScheme: 'light', acceptDownloads: true, }) } if (cookies && cookies.length > 0) { await gensparkContext.addCookies(cookies); } if (!gensparkPage) { gensparkPage = await gensparkContext.newPage() // 修改 webdriver 和 navigator 属性以避免自动化检测 await gensparkPage.addInitScript(() => { // 覆盖 webdriver 属性 Object.defineProperty(navigator, 'webdriver', { get: () => false, }); // 修改 user-agent 中的 HeadlessChrome 字符串 const userAgent = navigator.userAgent; if (userAgent.includes('HeadlessChrome')) { Object.defineProperty(navigator, 'userAgent', { get: () => userAgent.replace('HeadlessChrome', 'Chrome'), }); } // 添加语言和插件,使其看起来更像真实浏览器 Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en', 'zh-CN'], }); // 添加假的插件信息 Object.defineProperty(navigator, 'plugins', { get: () => { return [ { description: "Portable Document Format", filename: "internal-pdf-viewer", name: "Chrome PDF Plugin" }, { description: "Portable Document Format", filename: "mhjfbmdgcfjbbpaeojofohoefgiehjai", name: "Chrome PDF Viewer" }, { description: "Widevine Content Decryption Module", filename: "widevinecdmadapter.dll", name: "Widevine Content Decryption Module" } ]; }, }); // 创建假的 WebGL 渲染器信息 const getParameter = WebGLRenderingContext.prototype.getParameter; WebGLRenderingContext.prototype.getParameter = function (parameter) { // UNMASKED_VENDOR_WEBGL if (parameter === 37445) { return 'Intel Inc.'; } // UNMASKED_RENDERER_WEBGL if (parameter === 37446) { return 'Intel Iris OpenGL Engine'; } return getParameter.call(this, parameter); }; }); // 首次加载页面 await gensparkPage.goto('https://www.genspark.ai', { waitUntil: 'networkidle', timeout: 60000 }) console.log('GenSpark页面已初始化') } return gensparkPage } // 验证响应头值是否有效 function isValidHeaderValue(value: string): boolean { // 检查值是否为空或包含无效字符 if (!value || typeof value !== 'string') return false; // 检查是否包含换行符或回车符 if (/[\r\n]/.test(value)) return false; return true; } // 处理请求转发 async function handleRequest(url: string, method: string, headers: any, body?: any) { const browser = await initBrowser() const page = await browser.newPage() try { // 只移除确实需要移除的请求头 delete headers['host'] delete headers['connection'] delete headers['content-length'] delete headers['accept-encoding'] // 移除cf相关的头 delete headers['cdn-loop'] delete headers['cf-connecting-ip'] delete headers['cf-connecting-o2o'] delete headers['cf-ew-via'] delete headers['cf-ray'] delete headers['cf-visitor'] delete headers['cf-worker'] //移除其他无效的请求头 delete headers['x-direct-url'] delete headers['x-forwarded-for'] delete headers['x-forwarded-port'] delete headers['x-forwarded-proto'] headers['user-agent'] = userAgent console.log('处理请求:', method, url, headers, body) // 设置请求拦截器 await page.route('**/*', async (route: Route) => { const request = route.request() if (request.url() === url) { await route.continue({ method: method, headers: { ...request.headers(), ...headers }, postData: body }) } else { // 允许其他资源加载 await route.continue() } }) // 配置页面请求选项 const response = await page.goto(url, { waitUntil: 'domcontentloaded', // 改为更快的加载策略 timeout: 600000 }) if (!response) { throw new Error('未收到响应') } // 等待页面加载完成 await page.waitForLoadState('networkidle', { timeout: 5000 }).catch(() => { console.log('等待页面加载超时,继续处理') }) // 获取响应数据 const status = response.status() const responseHeaders = response.headers() // 确保移除可能导致解码问题的响应头 delete responseHeaders['content-encoding'] delete responseHeaders['content-length'] // 过滤无效的响应头 const validHeaders: Record = {} for (const [key, value] of Object.entries(responseHeaders)) { if (isValidHeaderValue(value as string)) { validHeaders[key] = value as string } else { console.warn(`跳过无效的响应头: ${key}: ${value}`) } } // 直接获取响应体的二进制数据 const responseBody = await response.body() console.log('请求处理完成:', status, responseBody.toString()) await page.close() return { status, headers: validHeaders, body: responseBody } } catch (error: any) { await page.close() console.error('请求处理错误:', error) throw new Error(`请求失败: ${error.message}`) } } // 添加静态文件服务 app.use('/public/*', serveStatic({ root: './' })) // 修改点 1: 处理根路由直接返回 index.html 内容,而不是重定向 app.get('/', async (c) => { try { const htmlContent = fs.readFileSync('./index.html', 'utf-8') return c.html(htmlContent) } catch (error) { console.error('读取index.html失败:', error) return c.text('无法读取主页', 500) } }) // 修改点 2: 添加 /genspark 路由来获取reCAPTCHA令牌 app.get('/genspark', async (c) => { try { const headers = Object.fromEntries(c.req.raw.headers) // Get the cookie string from headers const cookieString = headers.cookie || ''; // Parse cookies into an array of objects with name and value properties const cookies = cookieString.split(';').map(cookie => { const [name, value] = cookie.trim().split('='); return { name, value, domain: 'www.genspark.ai', path: '/' }; }).filter(cookie => cookie.name && cookie.value); const gensparkPage = await initGensparkPage(cookies) //刷新页面以确保获取新令牌 await gensparkPage.goto('https://www.genspark.ai/agents?type=moa_chat', { waitUntil: 'networkidle', timeout: 3600000 }) // 执行脚本获取令牌 const token = await gensparkPage.evaluate(() => { return new Promise((resolve, reject) => { // @ts-ignore window.grecaptcha.ready(function () { // @ts-ignore grecaptcha.execute( "6Leq7KYqAAAAAGdd1NaUBJF9dHTPAKP7DcnaRc66", { action: 'copilot' }, ).then(function (token: string) { resolve(token) }).catch(function (error: Error) { reject(error) }); }); // 设置超时 setTimeout(() => reject(new Error("获取令牌超时")), 10000); }); }).catch(error => { return c.json({ code: 500, message: '获取令牌失败' }) }); return c.json({ code: 200, message: '获取令牌成功', token: token }) } catch (error) { console.error('获取令牌失败:', error) if (gensparkPage) { await gensparkPage.close().catch(() => { }); gensparkPage = null; } if (gensparkContext) { await gensparkContext.close().catch(() => { }); gensparkContext = null; } return c.json({ code: 500, message: '获取令牌失败' }) } }) // 处理所有 HTTP 方法 app.all('*', async (c) => { const url = c.req.query('url') if (!url) { return c.text('Missing url parameter', 400) } try { const method = c.req.method const headers = Object.fromEntries(c.req.raw.headers) const body = method !== 'GET' ? await c.req.text() : undefined const result = await handleRequest(url, method, headers, body) // 创建标准响应 const response = new Response(result.body, { status: result.status, headers: new Headers({ ...result.headers, 'content-encoding': 'identity' // 显式设置不使用压缩 }) }) return response } catch (error) { console.error('Error:', error) return new Response('Internal Server Error', { status: 500, headers: new Headers({ 'content-type': 'text/plain' }) }) } }) // 清理函数 async function cleanup() { if (gensparkPage) { await gensparkPage.close().catch(() => { }); gensparkPage = null; } if (gensparkContext) { await gensparkContext.close().catch(() => { }); gensparkContext = null; } if (browser) { await browser.close().catch(() => { }); browser = null; } process.exit(0) } // 监听进程退出信号 process.on('SIGINT', cleanup) process.on('SIGTERM', cleanup) initGensparkPage().catch(async () => { if (gensparkPage) { await gensparkPage.close().catch(() => { }); gensparkPage = null; } if (gensparkContext) { await gensparkContext.close().catch(() => { }); gensparkContext = null; } }) const port = Number(process.env.PORT || '7860'); console.log(`Server is running on port http://localhost:${port}`) // 启动服务器 serve({ fetch: app.fetch, port: port })