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 与应用实例的对应关系是成功部署此类复杂应用的关键。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Python Flask框架
Python Flask框架

本专题专注于 Python 轻量级 Web 框架 Flask 的学习与实战,内容涵盖路由与视图、模板渲染、表单处理、数据库集成、用户认证以及RESTful API 开发。通过博客系统、任务管理工具与微服务接口等项目实战,帮助学员掌握 Flask 在快速构建小型到中型 Web 应用中的核心技能。

96

2025.08.25

Python Flask Web框架与API开发
Python Flask Web框架与API开发

本专题系统介绍 Python Flask Web框架的基础与进阶应用,包括Flask路由、请求与响应、模板渲染、表单处理、安全性加固、数据库集成(SQLAlchemy)、以及使用Flask构建 RESTful API 服务。通过多个实战项目,帮助学习者掌握使用 Flask 开发高效、可扩展的 Web 应用与 API。

73

2025.12.15

登录token无效
登录token无效

登录token无效解决方法:1、检查token的有效期限,如果token已经过期,需要重新获取一个新的token;2、检查token的签名,如果签名不正确,需要重新获取一个新的token;3、检查密钥的正确性,如果密钥不正确,需要重新获取一个新的token;4、使用HTTPS协议传输token,建议使用HTTPS协议进行传输 ;5、使用双因素认证,双因素认证可以提高账户的安全性。

6326

2023.09.14

登录token无效怎么办
登录token无效怎么办

登录token无效的解决办法有检查Token是否过期、检查Token是否正确、检查Token是否被篡改、检查Token是否与用户匹配、清除缓存或Cookie、检查网络连接和服务器状态、重新登录或请求新的Token、联系技术支持或开发人员等。本专题为大家提供token相关的文章、下载、课程内容,供大家免费下载体验。

830

2023.09.14

token怎么获取
token怎么获取

获取token值的方法:1、小程序调用“wx.login()”获取 临时登录凭证code,并回传到开发者服务器;2、开发者服务器以code换取,用户唯一标识openid和会话密钥“session_key”。想了解更详细的内容,可以阅读本专题下面的文章。

1077

2023.12.21

token什么意思
token什么意思

token是一种用于表示用户权限、记录交易信息、支付虚拟货币的数字货币。可以用来在特定的网络上进行交易,用来购买或出售特定的虚拟货币,也可以用来支付特定的服务费用。想了解更多token什么意思的相关内容可以访问本专题下面的文章。

1483

2024.03.01

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

424

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

213

2023.09.04

Golang处理数据库错误教程合集
Golang处理数据库错误教程合集

本专题整合了Golang数据库错误处理方法、技巧、管理策略相关内容,阅读专题下面的文章了解更多详细内容。

61

2026.02.06

热门下载

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

精品课程

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

共4课时 | 22.4万人学习

Django 教程
Django 教程

共28课时 | 4万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.5万人学习

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

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