在 Heroku 上使用 Django Rest Framework 后端部署 Angular 4 前端

Posted

技术标签:

【中文标题】在 Heroku 上使用 Django Rest Framework 后端部署 Angular 4 前端【英文标题】:Deploying an Angular 4 frontend with a Django Rest Framework backend on Heroku 【发布时间】:2018-02-18 20:23:40 【问题描述】:

我使用 Angular 4(使用 Angular CLI)构建了前端,使用 Django 和 Django Rest Framework 构建了后端。

开发环境的设置方式使得静态资产、html、JS 等都是 Angular 应用程序的一部分。 Angular 应用程序在由 CLI 在 localhost:4200 启动的服务器上运行,并通过 CORS 对 DRF API 的一系列 HTTP 调用与其余框架后端通信,该 API 位于另一个 localhost:8000 上,仅用于获取和服务信息。

如何在 Heroku 上将其部署为可用于生产的应用程序? heroku 指南说明了如何单独部署 Django 应用程序或单独部署 Angular 应用程序(在节点服务器上运行)。我是将它们部署为两个单独的实例还是将它们组合起来。如果是这样,我该怎么做?

【问题讨论】:

我最近在 digitalocean 的同一个 ubuntu 服务器上部署了一个 Angular 4 应用程序和 Django Rest Framework,前端位于 exmple.com,其余 api 位于 api.example.com。我从未使用过 Heroku,但如果您对我的部署到 ubuntu 服务器的解决方案感兴趣,我很乐意分享。 @jupiar,你能分享一下你的经验吗? @pdfarhad,我该怎么办,将其作为解决方案发布? @jupiar,如果你有任何博文,你可以分享。您也可以将其发布为解决方案。 :) @pdfarhad 我还没有博客,但我打算做一个。我现在就在这里分享它作为解决方案。 【参考方案1】:

此解决方案与如何在 Heroku 上执行此操作的请求不匹配,但应@pdfarhad 的请求完成。

首先,关于我曾经托管的内容,我的域名是在 Godaddy 注册的,它指向我在 Digitalocean 创建的服务器(droplet)。请注意,godaddy 上的 DNS 服务器指向 digitaloceans,ns1.digitalocean.comns2.digitalocean.comns3.digitalocean.com。然后在digitalocean的networking选项卡上,创建了两个A records,它们都指向我创建的服务器,一个是example.com,另一个是api.example.com

完成后,当您创建一个新的 Droplet 时,将通过电子邮件发送 root 用户的密码,然后执行:

# ssh root@<IPADDRESSOFSERVER>
# sudo apt-get update
# sudo adduser jupiar
# sudo usermod -aG sudo jupiar
# su - jupiar
$ sudo apt-get install nginx

此时,您应该可以导航到您的IPADDRESS并看到nginx登录页面,您可能需要等待一段时间才能让godaddy和digitalocean通过输入example.com,我想半天过去了名称服务器都已同步完毕。

现在,我刚刚在本地机器上设置了无密码 ssh:

$ ssh-keygen (no passphrase)
$ cat ~/.ssh/id_rsa.pub (then copy this)

现在在服务器上:

$ mkdir ~/.ssh
$ chmod 700 ~/.ssh
$ nano ~/.ssh/authorized_keys (paste the rsa you copied)
$ chmod 600 ~/.ssh/authorized_keys
$ sudo nano /etc/ssh/sshd_config
    | Make sure:
    | PasswordAuthentication no
    | PubkeyAuthentication yes
    | ChallengeResponseAuthentication no
$ sudo systemctl reload sshd
$ exit

现在您应该可以在没有密码的情况下通过 ssh 进入您的服务器了。

我使用 anaconda python 是因为我从事大量数据科学工作,所以:

$ wget https://repo.continuum.io/archive/Anaconda3-5.0.0.1-Linux-x86_64.sh
$ bash https://repo.continuum.io/archive/Anaconda3-5.0.0.1-Linux-x86_64.sh
    | installed to /home/jupiar/anaconda3, auto append path to .bashrc
$ . .bashrc
$ source .bashrc

现在,因为过去我在使用 python virtualenvs 运行 linux supervisor 时遇到了一些麻烦,所以我只是全局安装所有东西。 uwsgi 主要是 C 语言,所以你需要一些包来编译它。

$ sudo apt-get install build-essential python-dev python3-dev
$ pip install uwsgi

现在,做一个 git 仓库,你可以在服务器上做一个,但我更喜欢使用 github,因为它提供了很多有用的工具,也是项目贡献者之间协作的好地方,所以做一个私有仓库在github上,然后在你的本地机器上:(第三行是因为我用的是Mac)

新建一个文件夹,把所有东西都放进去

$ echo "# example" >> README
$ git init
$ find . -name .DS_Store -print0 | xargs -0 git rm -f --ignore-unmatch
$ echo ".DS_Store" >> .gitignore
$ git add .
$ git commmit -m "first commit"
$ git remote add origin https://github.com/<GITUSERNAME>/<REPONAME>.git
$ git push -u origin master

所以,再次在本地机器上,使用 scss 样式设置一个新的 angular 4 应用程序并跳过使其成为 git repo,因为它不会在 github 上正确显示,repo inside repo 等...:

$ ng new frontend --style=scss --skip-git

而且,我们将暂时保留应用程序,只需记住服务器将需要一个 dist 文件夹,您可以在前端文件夹中执行类似的操作,使用提前...:

$ ng build --aot -prod

现在再次在本地机器上,创建 Django Rest Framework 后端:

$ conda create -n exampleenv python=3.6 anaconda
$ source activate exampleenv
(exampleenv)$ pip install django
(exampleenv)$ pip install djangorestframework
(exampleenv)$ pip install django-cors-headers
(exampleenv)$ django-admin startproject backend
(exampleenv)$ cd backend
(exampleenv)$ django-admin startapp api
(exampleenv)$ python manage.py migrate
(exampleenv)$ python manage.py createsuperuser

现在,为了让最小的休息框架能够工作,我们需要:

settings.py 添加到INSTALLED APPS

'rest_framework',
'corsheaders',
'api',

settings.py 中添加到MIDDLEWARE顶部

'corsheaders.middleware.CorsMiddleware',

settings.py 添加:

CORS_ORIGIN_ALLOW_ALL = True

settings.py添加:

ALLOWED_HOSTS = ['<DIGITALOCEANSERVER-IP>', '*', 'localhost', '127.0.0.1']

backend/urls.py:

from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/', include('api.urls')),
]

api/models.py:

from django.db import models

# Create your models here.

class testModel(models.Model):
    word = models.CharField("word", max_length=20)

api/serializers.py:

from rest_framework import serializers
from .models import testModel

class testSerializer(serializers.ModelSerializer):
    word = serializers.CharField(max_length=20)

    class Meta: 
        model = testModel
        fields = ('id', 'word')

api/urls.py:

from django.conf.urls import url, include
from rest_framework.urlpatterns import format_suffix_patterns
from .views import testView

urlpatterns = [ 
    url(r'^test/', testView.as_view()),
]

api/views.py:

from rest_framework import generics
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import AllowAny
from django.shortcuts import render
from .models import testModel
from.serializers import testSerializer

# Create your views here.

class testView(APIView):
    def get(self, request):
        return Response('succeded?', 'yes')

现在保存了所有内容,如果您满足以下条件,它应该可以工作:

(exampleenv)$ python manage.py runserver
navigate to :8000/api/test/

Angular 4 前端和 DRF 后端都完成后,我们可以将更改推送到 github,现在这将是很多更改;)

现在,让我们将前端和后端放到服务器上,登录到服务器,如果您还没有的话,现在最好将 ssh 密钥从您的服务器(和本地计算机)添加到 github。在服务器上,我们可以通过:

$ ssh-keygen -t rsa -b 4096 -C "<EMAIL ADDRESS>"
$ eval "$(ssh-agent -s)"
Agent pid ....
$ ssh-add ~/.ssh/id_rsa
    Enter passphrase for /home/jupair/.ssh/id_rsa:
    Identity added: /home/jupiar/.ssh/id_rsa (/home/jupiar/.ssh/id_rsa)

$ mkdir example
$ cd example
$ git init
$ git pull git@github.com:<GITHUBUSERNAME>/<REPONAME>.git

(在某些时候,使用 https 或 ssh 可能会出错)如果您使用 ssh 密钥,则需要使用来自 github 的 ssh 存储库名称(在 github 上,clone or download 按钮将为您提供这些链接),在本地机器上你也可能需要 set-url 来使用 ssh 名称):

[on local machine]
$ git remote set-url origin git@github.com:<GITHUBUSERNAME>/<REPONAME>.git

好的,现在在您的服务器上,您的项目文件夹中应该有前端和后端文件夹,angular 很简单,在服务器上:

$ cd /etc/nginx/sites-available
$ sudo rm default
$ sudo nano frontend.conf

并在里面放置这样的东西:

server 
        listen 80;
        listen [::]:80;

        root /home/jupiar/example/frontend/dist;
        index index.html index.htm index.nginx-debian.html;

        server_name example.com;

        location / 
                try_files $uri $uri/ =404;
        

现在我们需要将该文件链接到启用的站点:

$ sudo ln -s /etc/nginx/sites-available/frontend.conf /etc/nginx/sites-enabled/frontend.conf
$ cd /etc/nginx/sites-enabled
$ sudo rm default
$ sudo systemctl restart nginx.service

前往 example.com,我们现在应该可以看到 Angular 应用正在运行,

好的,现在让后端可服务,有点棘手:

$ cd /etc/nginx/sites-available
$ sudo nano backend.conf

并放置如下内容:

server 
    listen 80;
    listen [::]:80;

    server_name api.example.com;

    location /static/admin 
        alias /home/jupair/anaconda3/lib/python3.6/site-packages/django/contrib/admin/static/admin;
    

    location /static/rest_framework 
        alias /home/jupiar/anaconda3/lib/python3.6/site-packages/rest_framework/static/rest_framework;
    

    location / 
        proxy_pass http://127.0.0.1:9000/;
        proxy_set_header    Host                $host;
        proxy_set_header    X-Real-IP           $remote_addr;
        proxy_set_header    X-Forwarded-For     $remote_addr;
        proxy_set_header    X-Forwarded-Proto   $scheme;
        proxy_redirect      off;

    

现在,将该文件链接到启用站点:

$ sudo ln -s /etc/nginx/sites-available/backend.conf /etc/nginx/sites-enabled/backend.conf

现在设置supervisor以使用uwsgi启动django app

$ sudo apt-get install supervisor
$ sudo nano /etc/supervisor/conf.d/backend_api.conf

在里面,有类似的东西:

[program:backend_api]
command = /home/jupiar/anaconda3/bin/uwsgi --http :9000 --wsgi-file /home/jupiar/example/backend/backend/wsgi.py
directory = /home/jupiar/example/backend
user = jupiar
autostart = true
autorestart = true
stdout_logfile = /var/log/backnd_api.log
stderr_logfile = /var/log/backend_api_err.log

现在,您需要运行:

$ sudo supervisorctl reread
$ sudo supervisorctl update
$ sudo supervisorctl restart backend_api
$ sudo systemctl restart nginx.service

现在,前往 api.example.com/api/test/ 应该会给您suceeded: true 的 django rest 框架响应。

从现在开始,只要您想实时进行更改,您就可以使用自定义 shell 脚本,就像这样:

cd /home/jupiar/example
git reset --hard (sometimes you may need to run this)
git pull git@github.com/<GITUSERNAME>/<PROJECTNAME>.git
sudo supervisorctl restart backend_api
sudo systemctl restart nginx.service

差不多就是这样,我相信一切都在那里,从我记得如何做,任何问题或如果有什么问题/对你不起作用,请发表评论并让我知道:)

【讨论】:

我的设置出现错误,您介意给我一些时间 @Jupiar。我面临类似的问题。我使用 angular s-s-r 和 django rest 框架。我想使用 digitalocean,但我使用 angular s-s-r 以及如何在 angular s-s-r 和 django rest 框架之间分割 digitalocean 服务器。 @user9714967 你好,我回答这个问题已经过去两年了,我现在已经完善了对 digitalocean、aws 等的部署策略,适用于各种不同的事情,所以这个答案似乎对我来说已经过时了。所以如果你问一个新问题,特别是关于 angular s-s-r,drf 和 digitalocean,然后在这里再次用链接发表评论,我很乐意通过更现代和更简单的方法提供详细的答案: ) ***.com/questions/57598339/… 这是我的问题的链接。谢谢你帮助我

以上是关于在 Heroku 上使用 Django Rest Framework 后端部署 Angular 4 前端的主要内容,如果未能解决你的问题,请参考以下文章

我的请求是跨源请求吗?(heroku 上的 Django rest api,CORS 没有阻止我的请求)

Django rest 框架,Django 通道,Ionic2 - websocket 握手错误

将 Cookiecutter-Django 应用程序部署到 Heroku 时出错

如何在 Heroku 上使用 Channels 和 Celery 部署 Django?

如何查看在 heroku 上运行的 rails 服务器,以便在发送 REST 请求时查看完整输出?

如何在 heroku 或 amazon web 服务上部署我的 rest api?