You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JS代理服务器请求Google数据遭拒,求解决实现方案

解决代理服务器请求Google被拒绝的问题

核心原因

你碰到的「www.google.com拒绝连接」是因为浏览器同源策略:前端JS不能直接跨域请求非同源的服务器资源,而Google的服务器也没有配置允许你的前端域名跨域访问的CORS规则,所以直接请求会被拦截。

代理服务器的核心逻辑是:用后端服务作为中间层,前端请求自己的后端,后端再去请求Google,最后把Google的响应返回给前端——绕过浏览器的同源限制。


实现步骤(用Node.js做后端,适配你的JS技术栈)

1. 搭建后端转发服务

先创建一个Node.js项目,安装依赖:

npm init -y
npm install express cors axios

创建server.js,写转发逻辑:

const express = require('express');
const cors = require('cors');
const axios = require('axios');
const https = require('https');

const app = express();
const PORT = 3000;

// 允许前端跨域请求
app.use(cors());
// 解析JSON请求体
app.use(express.json());
// 解析URL编码的请求体
app.use(express.urlencoded({ extended: true }));

// 处理Google搜索/页面请求的转发接口
app.get('/proxy/google', async (req, res) => {
  try {
    // 获取前端传入的目标URL或搜索关键词
    const { url, query } = req.query;
    let targetUrl;

    if (url) {
      // 如果是直接访问URL,直接转发
      targetUrl = url.startsWith('http') ? url : `https://${url}`;
    } else if (query) {
      // 如果是搜索关键词,构造Google搜索URL
      targetUrl = `https://www.google.com/search?q=${encodeURIComponent(query)}`;
    } else {
      // 默认返回Google首页
      targetUrl = 'https://www.google.com';
    }

    // 发送请求到Google,转发请求头(模拟浏览器)
    const response = await axios.get(targetUrl, {
      headers: {
        'User-Agent': req.headers['user-agent'] || 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36',
        'Accept': req.headers['accept'] || 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Language': req.headers['accept-language'] || 'en-US,en;q=0.5',
      },
      // 忽略SSL证书错误(如果遇到)
      httpsAgent: new https.Agent({ rejectUnauthorized: false }),
      // 允许重定向
      maxRedirects: 5,
    });

    // 把Google的响应返回给前端,包括状态码和响应头
    res.status(response.status);
    // 过滤掉可能导致问题的响应头
    const allowedHeaders = ['content-type', 'content-length', 'date', 'server'];
    Object.keys(response.headers).forEach(header => {
      if (allowedHeaders.includes(header.toLowerCase())) {
        res.setHeader(header, response.headers[header]);
      }
    });
    res.send(response.data);
  } catch (error) {
    console.error('转发请求出错:', error.message);
    res.status(error.response?.status || 500).send('请求失败:' + error.message);
  }
});

app.listen(PORT, () => {
  console.log(`代理后端运行在 http://localhost:${PORT}`);
});

启动后端:

node server.js

2. 修改前端JS,添加搜索功能

更新你的index.js,给搜索按钮绑定点击事件,调用后端接口:

let tabCount = 1;

function showTab(tabId) {
    const tabs = document.querySelectorAll('.tab-content');
    tabs.forEach(tab => {
        tab.classList.remove('active');
    });
    document.getElementById(tabId).classList.add('active');

    const tabElements = document.querySelectorAll('.tab');
    tabElements.forEach(tab => {
        tab.classList.remove('active');
    });
    event.target.classList.add('active');
}

function addNewTab() {
    tabCount++;
    const newTabId = `tab${tabCount}`;
    
    const newTab = document.createElement('div');
    newTab.className = 'tab';
    newTab.textContent = `Tab ${tabCount}`;
    newTab.setAttribute('onclick', `showTab('${newTabId}')`);
    document.querySelector('.add-tab').before(newTab);

    const newTabContent = document.createElement('div');
    newTabContent.id = newTabId;
    newTabContent.className = 'tab-content';
    newTabContent.innerHTML = `
        <img src="https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png" alt="Google Logo" class="logo">
        <div class="search-box">
            <input type="text" id="${newTabId}-search-input" placeholder="Search Google or type a URL">
            <button id="${newTabId}-search-btn" onclick="handleSearch('${newTabId}')">&#x1F50D;</button>
        </div>
        <div class="buttons">
            <button onclick="handleSearch('${newTabId}', true)">Google Search</button>
            <button onclick="handleLuckySearch('${newTabId}')">I'm Feeling Lucky</button>
        </div>
        <div id="${newTabId}-results" class="search-results">
            <iframe id="${newTabId}-iframe" class="search-iframe" style="width: 100%; height: 80vh; display: none;" frameborder="0"></iframe>
            <div id="${newTabId}-html-content" style="display: none; text-align: left; padding: 20px;"></div>
        </div>
    `;
    document.body.appendChild(newTabContent);
}

// 给初始的Tab1添加事件监听
document.addEventListener('DOMContentLoaded', () => {
    // 绑定Tab1的搜索按钮
    document.querySelector('#tab1 .search-box button').addEventListener('click', () => handleSearch('tab1'));
    document.querySelector('#tab1 .buttons button:first-child').addEventListener('click', () => handleSearch('tab1', true));
    document.querySelector('#tab1 .buttons button:last-child').addEventListener('click', () => handleLuckySearch('tab1'));
});

// 处理普通搜索
function handleSearch(tabId, isDirectSearch = false) {
    const input = document.getElementById(`${tabId}-search-input`);
    const query = input.value.trim();
    if (!query) return;

    const resultsDiv = document.getElementById(`${tabId}-results`);
    const iframe = document.getElementById(`${tabId}-iframe`);
    const contentDiv = document.getElementById(`${tabId}-html-content`);

    // 隐藏之前的内容
    iframe.style.display = 'none';
    contentDiv.style.display = 'none';

    let apiUrl;
    if (query.startsWith('http') || query.includes('.')) {
        // 如果是URL,直接转发
        apiUrl = `http://localhost:3000/proxy/google?url=${encodeURIComponent(query)}`;
        // 用iframe加载(因为直接渲染HTML可能有资源路径问题)
        iframe.src = apiUrl;
        iframe.style.display = 'block';
    } else {
        // 如果是搜索关键词
        apiUrl = `http://localhost:3000/proxy/google?query=${encodeURIComponent(query)}`;
        if (isDirectSearch) {
            // 直接用iframe加载搜索结果页
            iframe.src = apiUrl;
            iframe.style.display = 'block';
        } else {
            // 或者获取HTML内容渲染到页面(可能需要处理资源路径)
            fetch(apiUrl)
                .then(res => res.text())
                .then(html => {
                    // 替换HTML中的绝对路径为代理路径(可选,解决图片、CSS加载问题)
                    const proxiedHtml = html.replace(/https?:\/\/www\.google\.com/g, 'http://localhost:3000/proxy/google?url=https://www.google.com');
                    contentDiv.innerHTML = proxiedHtml;
                    contentDiv.style.display = 'block';
                })
                .catch(err => {
                    contentDiv.innerHTML = `<p>请求失败:${err.message}</p>`;
                    contentDiv.style.display = 'block';
                });
        }
    }
}

// 处理"I'm Feeling Lucky"
function handleLuckySearch(tabId) {
    const input = document.getElementById(`${tabId}-search-input`);
    const query = input.value.trim();
    if (!query) return;

    const iframe = document.getElementById(`${tabId}-iframe`);
    // 构造Google的I'm Feeling Lucky URL
    const luckyUrl = `https://www.google.com/search?q=${encodeURIComponent(query)}&btnI`;
    // 通过代理转发
    iframe.src = `http://localhost:3000/proxy/google?url=${encodeURIComponent(luckyUrl)}`;
    iframe.style.display = 'block';
}

关键注意事项

  • CORS配置:后端必须开启CORS,否则前端还是会被浏览器拦截。
  • 请求头模拟:必须转发浏览器的User-Agent等请求头,否则Google会识别为非浏览器请求,拒绝返回内容或触发反爬。
  • 资源路径处理:直接渲染Google的HTML时,里面的图片、CSS、JS路径是绝对路径,需要替换成通过你的代理后端访问的路径,否则这些资源会跨域加载失败(上面的代码里做了简单替换)。
  • 反爬机制:Google有严格的反爬,频繁请求可能会被封IP,建议添加Cookie转发、请求间隔控制等,或者使用代理IP池(进阶内容)。
  • HTTPS处理:如果要部署到线上,后端需要配置HTTPS,否则浏览器会阻止混合内容请求。

内容的提问来源于stack exchange,提问作者ermmmmm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 01:59:53