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

部署在Heroku的Flask应用首次访问正常,页面重载后报连接拒绝错误

故障原因
  • 核心触发点:Selenium的Chrome驱动实例被定义为全局启动对象,且在第一次请求的finally块中执行了driver.quit()。首次请求到达时,全局初始化的驱动处于可用状态,因此访问正常;但第一次请求处理完成后,驱动进程被直接销毁,后续所有重载/新请求再调用已经退出的驱动发起访问时,无法连接到本地Chrome服务,最终从底层抛出ConnectionRefusedError,逐层往上包装为NewConnectionError、MaxRetryError。
  • 代码附带的其他隐患:
    • 缺少import os模块导入,依赖环境变量读取Chrome、驱动路径的逻辑在部署环境下会直接抛出名称错误
    • 异常处理逻辑存在漏洞:如果WebDriverWait等待元素超时,element变量不会被赋值,此时直接在finally块读取element.text会触发变量未定义错误
    • 启动逻辑未适配Heroku部署规则:Flask默认监听127.0.0.1:5000,无法接收Heroku平台动态路由转发的外部请求
    • 代码中使用的xpath变量未提前定义,运行时会直接抛出名称错误
修复方案
  1. 移除全局初始化的driver实例,改为每个请求单独创建driver实例,请求处理完成(无论成功失败)后再销毁当前请求对应的driver,从根源避免跨请求调用已销毁实例的问题。
  2. 补上缺失的模块导入,修正异常处理逻辑,保证driver初始化成功后才会执行退出操作,避免空对象报错。
  3. 适配Heroku的端口分配规则,监听平台动态下发的PORT环境变量,绑定0.0.0.0地址保证外部请求可达。

修复后的可直接部署代码如下:

import os
from flask import Flask
from flask import request
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException

app = Flask(__name__)

def init_chrome_driver():
    chrome_options = webdriver.ChromeOptions()
    chrome_options.binary_location = os.environ.get("GOOGLE_CHROME_BIN")
    chrome_options.add_argument("--headless")
    chrome_options.add_argument("--disable-dev-shm-usage")
    chrome_options.add_argument("--no-sandbox")
    chrome_options.add_argument("--disable-gpu")
    chrome_options.add_argument("--remote-debugging-port=9222")
    driver = webdriver.Chrome(
        executable_path=os.environ.get("CHROMEDRIVER_PATH"),
        options=chrome_options
    )
    return driver

@app.route('/', methods=['GET', 'POST'])
def handleRequests():
    driver = None
    resp_data = ""
    target_url = str(request.args.get('url'))
    # 替换为实际业务需要匹配的XPath规则
    target_xpath = "//*[@id='content']"
    try:
        driver = init_chrome_driver()
        driver.get(target_url)
        element = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.XPATH, target_xpath))
        )
        resp_data = element.text
    except TimeoutException:
        resp_data = "页面目标元素加载超时"
    except Exception as e:
        resp_data = f"请求处理失败: {str(e)}"
    finally:
        if driver:
            driver.quit()
        return str(resp_data)
    
if __name__ == "__main__":
    listen_port = int(os.environ.get("PORT", 5000))
    app.run(host="0.0.0.0", port=listen_port)

补充说明:如果是低流量场景,单请求创建销毁driver实例的逻辑足够稳定;如果后续请求量上升,可以自行实现driver连接池复用实例,降低频繁启动销毁浏览器带来的性能开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 09:45:29