如何从 Heroku 上的 Django 项目正确地提供我的 Angular 应用程序静态文件?
Posted
技术标签:
【中文标题】如何从 Heroku 上的 Django 项目正确地提供我的 Angular 应用程序静态文件?【英文标题】:How to properly serve my Angular application static files from a Django project on Heroku? 【发布时间】:2018-12-08 14:21:21 【问题描述】:我正在尝试在 Heroku 上部署我使用 Django 2、DRF 和 Angular 6 构建的应用程序,并且努力获取我的 Angular 应用程序的静态文件。我在开发环境和 Heroku 上都使用 WhitheNoise。 项目结构如下:
my_project/
|-frontend/
| |- dist/
| |- ...
|-myproject/
| |-settings/
| | |- __init.py
| | |- base.py
| | |- prod.py
| | |- dev.py
| |- __init__.py
| |- urls.py
| |- views.py
| |- wsgi.py
|-other_app1/
| |- ...
|-other_app2/
| |- ...
|-staticfiles/
| |-....
|-manage.py
|-Procfile
|-requirements.txt
我已经以这样的方式配置 Heroku,每次部署我的应用程序时,都会构建我的 Angular 应用程序,因此在 frontend/dist/ 中生成静态文件,然后运行 collectstatic 并将它们复制到我的静态文件文件夹中我的项目的根。我的设置是:
ANGULAR_APP_DIR = os.path.join(BASE_DIR, 'frontend/dist')
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'
STATICFILES_DIRS = [
('frontend', os.path.join(ANGULAR_APP_DIR)),
]
这很好用,并将我的 Angular 应用程序的所有文件收集到 staticfiles/ 中,并带有一个名为 frontend/ 的文件夹
我的问题是现在我正在尝试为位于 staticfiles/frontend 中的 index.html 文件提供服务,但我无法使其工作:
urls.py
urlpatterns = [
path('', HomePageView.as_view()), #first one
# .... Other urls
]
views.py
from django.views import static
# Serves the index page
class HomePageView(TemplateView):
def get(self, request, **kwargs):
return static.serve(request,'index.html', 'staticfiles')
这会找到并提供 index.html 文件,但无法成功提供我的应用程序运行所需的其余 js 文件(polyfills、main、styles...),因为未附加“/static/”自动发送到请求它们的 url。 有人知道我如何告诉 Django 或 Heroku 在 staticfiles/frontend 文件夹下找到它们吗?
生成的 index.html 如下所示:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Angular Project</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="styles.578ada0b0e3742b4b4bb.css"></head>
<body class="with-top-navbar">
<app-root></app-root>
<script type="text/javascript" src="runtime.92d800a8cdfd75f49eae.js"></script>
<script type="text/javascript" src="polyfills.7ee4ee2275a8c5d5ea6f.js"></script>
<script type="text/javascript" src="main.4aeccc46b72bbab58fd0.js"></script></body>
</html>
我的控制台的输出是:
[29/Jun/2018 13:31:30] "GET / HTTP/1.1" 200 638
Not Found: /styles.578ada0b0e3742b4b4bb.css
Not Found: /runtime.92d800a8cdfd75f49eae.js
[29/Jun/2018 13:31:30] "GET /styles.578ada0b0e3742b4b4bb.css HTTP/1.1" 404 2353
Not Found: /polyfills.7ee4ee2275a8c5d5ea6f.js
Not Found: /main.4aeccc46b72bbab58fd0.js
[29/Jun/2018 13:31:30] "GET /polyfills.7ee4ee2275a8c5d5ea6f.js HTTP/1.1" 404 2359
[29/Jun/2018 13:31:30] "GET /runtime.92d800a8cdfd75f49eae.js HTTP/1.1" 404 2353
[29/Jun/2018 13:31:30] "GET /main.4aeccc46b72bbab58fd0.js HTTP/1.1" 404 2344
Not Found: /styles.578ada0b0e3742b4b4bb.css
[29/Jun/2018 13:31:32] "GET /styles.578ada0b0e3742b4b4bb.css HTTP/1.1" 404 2353
Not Found: /runtime.92d800a8cdfd75f49eae.js
[29/Jun/2018 13:31:32] "GET /runtime.92d800a8cdfd75f49eae.js HTTP/1.1" 404 2353
Not Found: /polyfills.7ee4ee2275a8c5d5ea6f.js
[29/Jun/2018 13:31:32] "GET /polyfills.7ee4ee2275a8c5d5ea6f.js HTTP/1.1" 404 2359
Not Found: /main.4aeccc46b72bbab58fd0.js
[29/Jun/2018 13:31:32] "GET /main.4aeccc46b72bbab58fd0.js HTTP/1.1" 404 2344
另外,请注意,我不想手动编辑生成的 index.html,也不想将其放在其他地方,因为这会改变我的部署工作流程。
另外,我知道 django.views.statics.serve 不适合生产环境,所以如果您知道如何以其他方式提供此文件,也欢迎提示
谢谢!
【问题讨论】:
【参考方案1】:最后,我可以通过安装这个漂亮的包自己解决这个问题:django-spa,它建立在 whitenoise 之上,可以直接从静态文件根文件夹提供来自 SPA 的索引和文件。
包here的使用示例
另外,我必须从收集静态填充的目录中删除“前端”文件夹:
STATICFILES_DIRS = [
os.path.join(ANGULAR_APP_DIR),
]
并删除我用于在“/”上提供索引的视图:
urlpatterns = [
# The following SPA settings are handled in Django-SPA
# - everything not matched in Django's urlpatterns goes to /
# - index.html served on /
# - all /static/... files served on /...
# other views....
path('admin/', admin.site.urls),
]
感谢@metakermit 的包裹!
【讨论】:
感谢您的回答。我现在面临同样的问题。我按照手册操作,然后我请求“/”页面,我得到了 PageNotFound。您是否对项目进行了任何具体更改?【参考方案2】:您可以使用render
from django.shortcuts import render
return render(request, 'index.html', )
静态文件需要加/static/
like
% load static %
<script type="text/javascript" src="% static "polyfills.7ee4ee2275a8c5d5ea6f.js" %"></script>
【讨论】:
render 要求我的 index.html 在某个模板文件夹下,而我的不在。另外,我不想手动编辑索引,除非这是唯一的方法【参考方案3】:如果您不喜欢使用软件包,可以尝试以下方法
settings.py
ANGULAR_APP_DIR = os.path.join(BASE_DIR, 'path/to/your/angular/app/dist')
STATICFILES_DIRS = [
os.path.join(ANGULAR_APP_DIR),
]
STATICFILES_STORAGE = os.environ.get('STATICFILES_STORAGE', "whitenoise.storage.CompressedManifestStaticFilesStorage")
WHITENOISE_ROOT = STATIC_ROOT
WHITENOISE_INDEX_FILE = True
步骤:
ng build
python manage.py collectstatic --no-input --clear
python manage.py runserver
Reference
【讨论】:
以上是关于如何从 Heroku 上的 Django 项目正确地提供我的 Angular 应用程序静态文件?的主要内容,如果未能解决你的问题,请参考以下文章
通过 Gunicorn 在 Heroku 上的 Django-twoscoops-project(骨架)。如何设置Procfile?
RabbitMQ 上的 Heroku、Django 和 celery
错误:无法从“10.3”确定 PostgreSQL 版本 - Heroku 上的 Django
django makemigrations 和 heroku 服务器上的迁移不创建表