Heroku部署Django DRF遇媒体类型错误及PostgreSQL连接问题
Django DRF + PostgreSQL Heroku部署全指南(附问题排查)
你的问题复盘
我最近把纯API的Django项目用Gunicorn部署到Heroku后,遇到两个棘手问题:
- 调用
<Heroku域名>/api/login接口时,明明前端已经设置了content-type: application/json并提交JSON数据,却返回错误:"detail": "Unsupported media type \"application/x-www-form-urlencoded\" in request.",但本地完全正常。 - 数据库连接失败,日志显示尝试连接localhost的5432端口,返回503/500错误,只有手动执行
heroku pg:psql postgresql-shaped-60432 --app <应用名>才好像能暂时解决,但每次部署都要手动操作太麻烦。
当前我的配置:
- 视图里已在非文件上传接口设置
parser_classes = [JSONParser],文件上传用FileUploadParser - 前端请求头配置:
const token_config = { headers: { 'content-type': 'application/json', accept: 'application/json', 'Authorization': 'Bearer ${token}', //withCredentials : true, }, }; - requirements.txt内容:
Django==3.1.1 django-allauth==0.42.0 django-cors-headers==3.5.0 django-environ==0.4.5 django-rest-auth==0.9.5 django-sslserver==0.20 djangorestframework==3.11.1 djangorestframework-simplejwt==4.1.3 gunicorn==20.0.4 image==1.5.27 importlib-metadata==1.7.0 oauthlib==3.1.0 Pillow==7.2.0 psycopg2-binary==2.8.2 PyJWT==1.7.1
核心疑问解答+分步解决方案
一、settings.py怎么配置才能和本地表现一致?
这是解决两个问题的核心,重点关注以下几个部分:
1. 跨域与DRF解析器配置
媒体类型错误的根源大概率是请求头没有被正确接收或者DRF全局解析器配置缺失:
- 首先确保CORS中间件在settings.py的
MIDDLEWARE里顺序正确(必须放在django.middleware.common.CommonMiddleware之前):MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 其他中间件... ] - 全局配置DRF的解析器,避免单个视图配置遗漏:在settings.py末尾添加:
REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', # 如果需要支持表单提交,可保留FormParser,但你的场景只需要JSON # 'rest_framework.parsers.FormParser', ], # 其他DRF配置,比如权限类、认证类... } - 检查前端请求的小坑:你写的
'Authorization': 'Bearer ${token}'用了单引号,模板字符串变量替换必须用反引号包裹整个字符串,否则${token}会被当成字面量,修正为:const token_config = { headers: { 'content-type': 'application/json', accept: 'application/json', 'Authorization': `Bearer ${token}`, // 这里用反引号 }, };
2. 数据库配置(彻底解决连接localhost问题)
Heroku的PostgreSQL是托管服务,绝对不能硬编码localhost,必须用环境变量读取:
- 用django-environ加载Heroku的
DATABASE_URL环境变量(你已经安装了django-environ,直接用):import environ import os env = environ.Env( DEBUG=(bool, False) ) # 读取本地.env文件(开发环境用),Heroku上会自动忽略,因为环境变量已设置 environ.Env.read_env(os.path.join(BASE_DIR, '.env')) # 数据库配置 DATABASES = { 'default': env.db(), } # 保持数据库连接,避免频繁断开 DATABASES['default']['CONN_MAX_AGE'] = 500 - 确保
ALLOWED_HOSTS包含你的Heroku域名:ALLOWED_HOSTS = ['<你的应用名>.herokuapp.com', 'localhost', '127.0.0.1'] - 生产环境必须关闭DEBUG:
DEBUG = env('DEBUG') # 本地.env里设DEBUG=True,Heroku上用heroku config:set DEBUG=False设置
二、部署后需要手动启动数据库吗?绝对不需要!
你遇到的数据库连接错误,根本原因是settings.py里数据库配置还是指向localhost,不是因为需要手动启动数据库。正确的流程是:
- 部署前先在Heroku添加PostgreSQL插件(如果还没加):
heroku addons:create heroku-postgresql:hobby-dev --app <你的应用名> - 部署后执行数据库迁移(创建表结构):
heroku run python manage.py migrate --app <你的应用名> - 不需要手动进psql,除非你要手动操作数据库。如果还是出现连接错误,检查:
- 有没有运行
heroku config:set SECRET_KEY=<你的密钥>?Heroku上必须设置SECRET_KEY,不能用本地的。 - 查看Heroku的环境变量:
heroku config --app <你的应用名>,确认DATABASE_URL存在。
- 有没有运行
完整的Heroku部署流程(走一遍避免遗漏)
- 项目根目录创建
Procfile(无后缀),内容:
比如你的项目名叫myapi,那就是web: gunicorn <你的项目名>.wsgi --log-file -web: gunicorn myapi.wsgi --log-file - - 本地创建
.env文件(加入.gitignore,不要提交到Git),内容:DEBUG=True SECRET_KEY=你的本地密钥 DATABASE_URL=postgres://localhost:5432/你的本地数据库名 - 提交代码到Git:
git add . git commit -m "Prepare for Heroku deployment" - 推送代码到Heroku:
git push heroku main - 设置Heroku环境变量:
heroku config:set DEBUG=False SECRET_KEY=你的生产环境密钥 --app <你的应用名> - 执行迁移:
heroku run python manage.py migrate --app <你的应用名> - 查看日志排查问题:
heroku logs --tail --app <你的应用名>
内容的提问来源于stack exchange,提问作者ninja
相关产品推荐
相关产品推荐

