0

0

Heroku 上 Flask API 与 Dash 应用的部署与集成

花韻仙語

花韻仙語

发布时间:2025-09-25 15:08:01

|

668人浏览过

|

来源于php中文网

原创

Heroku 上 Flask API 与 Dash 应用的部署与集成

本文探讨了在 Heroku 部署 Flask API 与 Dash 应用时常见的 405 Method Not Allowed 错误及其解决方案。核心问题在于 Heroku 的 Procfile 配置与 Flask 和 Dash 应用实例的交互方式。通过将 Dash 应用集成到主 Flask 实例中,并正确配置 Procfile 指向单一的 Flask 应用入口,可以有效解决路由冲突,实现 API 和 UI 的协同工作。教程将提供集成示例代码,并强调部署注意事项。

1. 背景与问题描述

在 heroku 平台部署 web 应用时,开发者常遇到将后端 api(如使用 flask 构建)与前端交互式界面(如使用 dash 构建)结合的需求。一个典型的场景是,flask api 负责数据接收和处理(例如,将远程数据写入 postgresql 数据库),而 dash 应用则提供数据可视化或管理界面。然而,当尝试在同一个 heroku 应用中同时运行这两个组件时,可能会遭遇 405 method not allowed 错误,尤其是在尝试向 flask api 端点发送 post 请求时。

原始问题中的错误信息 response content: b'a style="color:#f60; text-decoration:underline;" title= "html"href="https://www.php.cn/zt/15763.html" target="_blank">html>\n\n

405 Method Not Allowed\n

Method Not Allowed

\n

The method is not allowed for the requested URL.

\n' 明确指出服务器不接受对指定 URL 使用请求的方法(POST)。这通常不是认证问题,而是路由或服务器配置问题。

2. 深入理解问题根源:Flask、Dash 与 Heroku Procfile

问题的核心在于 Flask 和 Dash 应用实例的独立性以及 Heroku Procfile 的工作方式。

在提供的代码中,存在两个独立的应用程序实例:

  1. app = Flask(__name__):这是一个标准的 Flask 应用实例,用于定义 API 路由(例如 /ingest)。
  2. dash_app = dash.Dash(__name__,):这是一个 Dash 应用实例,它内部也运行着一个 Flask 服务器 (dash_app.server)。

当在 Procfile 中定义 Heroku 的 Web 进程时,我们必须指定一个单一的入口点供 Gunicorn(Heroku 推荐的 WSGI HTTP 服务器)启动。

  • 如果 Procfile 指向 your_module_name:app,Gunicorn 将启动 app = Flask(__name__) 实例。此时,@app.route 定义的 API 路由将可用,但 dash_app 及其路由将无法访问。
  • 如果 Procfile 指向 your_module_name:server(这里的 server 通常指 dash_app.server),Gunicorn 将启动 Dash 应用内部的 Flask 实例。此时,Dash 界面将可用,但 app = Flask(__name__) 实例上定义的 API 路由将无法访问,从而导致 405 Method Not Allowed 错误,因为 /ingest 路径对于 Dash 应用的内部 Flask 实例而言可能不存在或不允许 POST 方法。

简而言之,尝试在同一个 Heroku dyno 中通过单一 Procfile 入口同时运行两个独立的 Flask/Dash 实例是行不通的。

破浪分红权返利系统基础版
破浪分红权返利系统基础版

破浪分红权返利系统是在破浪直销系统的基础上独立自主开发的一套稳定完善的购物商场网站管理系统,系统基于PHP+MYSQL开发,集购物商城、积分商城、商家联盟、会员营销机制等一体,模板与程序分离,集成网上支付,嵌入型短信应用API集成,使用简单、功能强大,多种返现模式可自由选择,为广大创业者者提供一个快速、高效、稳定、安全的电子商务系统。系统集O2O\C2C\B2C\B2B2C以及直销、分红、代理、分

下载

3. 解决方案:将 Dash 应用集成到现有 Flask 应用中

最推荐且最健壮的解决方案是将 Dash 应用作为子应用集成到主 Flask 应用中。这样,所有路由(无论是 Flask API 路由还是 Dash UI 路由)都将由同一个 Flask 服务器实例处理。

3.1 修正后的应用代码

以下是整合了 Flask API 和 Dash UI 的 Python 应用代码示例:

from flask import Flask, request, jsonify, make_response
from flask_cors import CORS
import dash
from dash import dcc, html, Input, Output
import json
import os # 用于获取数据库连接字符串

# 1. 创建主 Flask 应用实例
app = Flask(__name__)
CORS(app) # 为主 Flask 应用启用 CORS

# 2. 将 Dash 应用集成到现有的 Flask 应用中
# 通过 server=app 参数,Dash 会使用我们已经创建的 Flask 应用实例
# url_base_pathname 可以指定 Dash 应用的根路径,例如 /dashboard/
dash_app = dash.Dash(__name__, server=app, url_base_pathname='/dashboard/')

# 3. 定义 Flask API 路由
# 这个路由现在属于主 Flask 应用
@app.route('/ingest', methods=['OPTIONS', 'POST'])
def handle_ingest():
    # 处理 CORS 预检请求
    if request.method == 'OPTIONS':
        response = make_response()
        response.headers.add('Access-Control-Allow-Origin', '*') # 生产环境请指定具体域名
        response.headers.add('Access-Control-Allow-Headers', 'Authorization, Content-Type')
        response.headers.add('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
        return response

    # 认证逻辑
    token = request.headers.get('Authorization')
    # 客户端发送的是 'Bearer too_many_secrets',所以这里也要匹配
    valid_tokens = ["Bearer too_many_secrets"] 

    if token in valid_tokens:
        data = request.json # 假设数据以 JSON 格式发送

        # --- 在这里执行数据验证和写入 PostgreSQL 数据库的逻辑 ---
        # 示例:连接到 Heroku Postgres 数据库并插入数据
        # import psycopg2
        # DATABASE_URL = os.environ.get('DATABASE_URL') # Heroku 会自动提供
        # try:
        #     conn = psycopg2.connect(DATABASE_URL, sslmode='require')
        #     cur = conn.cursor()
        #     # 示例:创建一个表并插入数据
        #     # cur.execute("CREATE TABLE IF NOT EXISTS sensor_data (id SERIAL PRIMARY KEY, sensor TEXT, value REAL, timestamp TIMESTAMPTZ DEFAULT NOW());")
        #     # cur.execute("INSERT INTO sensor_data (sensor, value) VALUES (%s, %s);", (data.get('sensor'), data.get('value')))
        #     conn.commit()
        #     cur.close()
        #     conn.close()
        #     print(f"Data ingested successfully: {data}")
        #     return jsonify({"message": "Data ingested successfully", "received_data": data}), 200
        # except Exception as e:
        #     print(f"Database error: {e}")
        #     return jsonify({"message": "Failed to ingest data due to database error"}), 500

        # 仅为演示,实际应写入数据库
        print(f"Success: Data ingested successfully: {data}")
        return jsonify({"message": "Data ingested successfully", "received_data": data}), 200
    else:
        print("Unauthorized user: Your token was Invalid")
        return jsonify({"message": "Unauthorized"}), 401

# 4. 定义 Dash 应用的布局和回调
# Dash 应用现在是主 Flask 应用的一个部分
dash_app.layout = html.Div(children=[
    html.H1(children='Heroku 集成应用'),
    html.P('欢迎来到 Dash 仪表板!'),
    dcc.Link('访问数据摄取 API 端点', href='/ingest', refresh=True), # 链接到 Flask API
    html.Div(id='output-message', style={'margin-top': '20px'})
])

# 示例 Dash 回调 (如果需要)
# @dash_app.callback(
#     Output('output-message', 'children'),
#     Input('url', 'pathname') # 需要 dcc.Location 组件才能获取 pathname
# )
# def display_page(pathname):
#     if pathname == '/dashboard/':
#         return html.Div("您正在查看 Dash 仪表板首页。")
#     elif pathname == '/ingest':
#         return html.Div("您已点击了 API 端点链接,但此页面本身不提供交互。")
#     return html.Div("未知页面")


# 5. 主程序入口
if __name__ == '__main__':
    # 在本地运行,Flask 应用将作为主服务器
    app.run(debug=True)

3.2 客户端请求脚本

客户端请求脚本保持不变,因为它只需知道 API 端点。

import requests

data = {
    "sensor": "temperature",
    "value": 25.5
}

# 假设 Heroku 应用的 URL 是 'https://my_app.herokuapp.com/'
# API 端点现在是 '/ingest'
api_endpoint = 'https://my_app.herokuapp.com/ingest'  
token = 'too_many_secrets' # 客户端的原始 token

headers = {'Authorization': f'Bearer {token}'} # 按照约定发送 Bearer token

response = requests.post(api_endpoint, json=data, headers=headers, verify=True)

if response.status_code == 200:
    print("Data sent successfully")
    print(f"Response: {response.json()}")
else:
    print(f"Failed to send data. Status code: {response.status_code}")
    print(f'Response content: {response.content.decode()}') # 解码以便阅读

3.3 Heroku Procfile 配置

由于我们将 Dash 集成到了主 Flask 应用 app 中,现在只需要 Procfile 指向这个主 Flask 应用实例。 假设你的 Python 文件名为 app.py:

web: gunicorn app:app

这里的 app:app 表示:

  • app (第一个):指的是你的 Python 模块文件名(例如 app.py)。
  • app (第二个):指的是该模块中 Gunicorn 应该启动的 Flask 应用程序实例的变量名 (app = Flask(__name__))。

4. 部署注意事项

  1. 依赖管理: 确保 requirements.txt 文件中包含了所有必要的库,例如 flask, dash, dash-core-components, dash-html-components, flask-cors, gunicorn, psycopg2 (如果使用 PostgreSQL)。
  2. 环境变量: 对于敏感信息(如数据库连接字符串、API 密钥),应使用 Heroku 环境变量而非硬编码。例如,Heroku 会自动为 Heroku Postgres 数据库提供 DATABASE_URL 环境变量。
  3. CORS 配置: 在生产环境中,Access-Control-Allow-Origin: '*' 应该被替换为你的前端应用或客户端的特定域名,以增强安全性。
  4. 授权令牌: 确保客户端发送的授权令牌格式(例如 Bearer )与服务器端验证的格式一致。
  5. Gunicorn 配置: 如果需要更高级的 Gunicorn 配置(例如工作进程数量、超时时间),可以在 Procfile 中添加参数或创建 gunicorn.conf.py 文件。
  6. 数据库连接: 在 Heroku 上连接 PostgreSQL 数据库时,通常需要 psycopg2-binary 库,并且连接字符串(DATABASE_URL)会自动注入到环境中。

5. 总结

通过将 Dash 应用作为子应用集成到主 Flask 应用中,并确保 Procfile 正确指向这个统一的 Flask 实例,我们能够成功地在 Heroku 上部署一个同时提供 API 服务和交互式 UI 的应用。这种方法避免了多个应用实例之间的冲突,简化了部署和管理,并解决了 405 Method Not Allowed 这一常见的部署问题。理解 Heroku Procfile 与应用实例的对应关系是成功部署此类复杂应用的关键。

相关专题

更多
python开发工具
python开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

760

2023.06.15

python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

639

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

762

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

618

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

1265

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

549

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

579

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

709

2023.08.11

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

72

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 4.4万人学习

Django 教程
Django 教程

共28课时 | 3.2万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号