Nginx Nuxt.js Django REST框架实现


首先

在上一篇文章的基础上,我将在nginx的Nuxt.js Django REST框架上运行一个应用程序。

配置图

有以下四个容器。
自上次发布以来,我已经添加了一个nginx容器。
image.png

?首页显示
①通过nginx 访问nuxt容器
②带nuxt容器的SSR。这时,请点击API以从django获取数据库信息。
③将呈现的页面返回给用户
image.png

?当您点击页面中的API时
通过nginx访问django容器,并将结果返回给用户。
image.png

环境

Window10 Pro
Docker桌面v2.1.0.5
Python 3.6.9
django 2.2.7
djangorestframework 3.10.3
Nuxt.js v2.11.0
nginx 1.13.12

目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
.
├─django
│  ├─manage.py
│  ├─composeexample
│  │   ├─settings.py
│  │   ├─urls.py
│  │   ├─wsgi.py
│  │   └─__init__.py
│  └─myapp
│      ├─migrations
│      ├─admin.py
│      ├─apps.py
│      ├─models.py
│      ├─renderers.py
│      ├─serializers.py
│      ├─tests.py
│      ├─urls.py
│      ├─views.py
│      └─__init__.py

├─docker-compose.yml

├─dockerfiles
│  ├─django_docker
│  │   ├─dockerfile
│  │   └─requirements.txt
│  └─nuxt_docker
│      └─dockerfile

├─mysql
│  └─conf.d

├─nginx
│  ├─uwsgi_params
│  └─conf
│      └─app_nginx.conf

└─nuxt
    └─front
       └─以下略

自上次以来的变化

在上一篇文章中,它是在SPA中设置的,但是这次我们将继续在SSR中进行设置。

./nuxt/front/nuxt.config.js

1
2
export default {
  mode: 'universal', //SSRに変更

建筑nginx

编辑docker-compose.yml

将nginx设置添加到docker-compose.yml中。
分配端口80。

./docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
version: '3'

services:
  db:
    image: mysql:latest
    restart: always
    container_name: mysql
    environment:
      MYSQL_ROOT_PASSWORD: test
      MYSQL_USER: test
      MYSQL_DATABASE: test
      MYSQL_PASSWORD: test
    ports:
      - 3306:3306
    expose:
      - 3306
    volumes:
      - mysqldata:/var/lib/mysql
      - ./mysql/conf.d:/etc/mysql/conf.d

  web:
    container_name: django
    build: ./dockerfiles/django_docker
    command:
      python3 manage.py runserver 0.0.0.0:8000
    volumes:
      - ./django:/code
    ports:
      - "8000:8000"
    depends_on:
      - db

  front:
    container_name: nuxt
    build: ./dockerfiles/nuxt_docker
    tty: true
    volumes:
      - ./nuxt:/code
    ports:
      - "3000:3000"

#ここから

  nginx:
    image: nginx:1.13
    container_name: nginx
    ports:
      - "80:80"

#ここまで

volumes:
  mysqldata:

让我们从这里开始一次nginx。
确认docker ps已启动。

1
2
3
4
5
> docker-compose up -d nginx

> docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                                                                      NAMES
aa3fe475db52        nginx:1.13          "nginx -g 'daemon of…"   About a minute ago   Up About a minute   0.0.0.0:80->80/tcp                                                         nginx

如果访问

http:// localhost /并显示以下屏幕,则说明操作成功。
image.png

Django方面的变化

添加nginx配置文件

添加以下目录和文件。

1
2
3
4
5
.
└─nginx
   ├─uwsgi_params
   └─conf
       └─app_nginx.conf

以下是使用uWSGI的设置。

uwsgi_params

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
uwsgi_param  QUERY_STRING       $query_string;
uwsgi_param  REQUEST_METHOD     $request_method;
uwsgi_param  CONTENT_TYPE       $content_type;
uwsgi_param  CONTENT_LENGTH     $content_length;

uwsgi_param  REQUEST_URI        $request_uri;
uwsgi_param  PATH_INFO          $document_uri;
uwsgi_param  DOCUMENT_ROOT      $document_root;
uwsgi_param  SERVER_PROTOCOL    $server_protocol;
uwsgi_param  REQUEST_SCHEME     $scheme;
uwsgi_param  HTTPS              $https if_not_empty;

uwsgi_param  REMOTE_ADDR        $remote_addr;
uwsgi_param  REMOTE_PORT        $remote_port;
uwsgi_param  SERVER_PORT        $server_port;
uwsgi_param  SERVER_NAME        $server_name;

以下是nginx的设置。
目标由路径分隔,因此与/ api和/ admin的通信将到达Django容器的端口8000。
除此之外,我将其设置为通过HTTP进入nuxt容器的端口3000。
参考

./nginx/conf/app_nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
upstream django {
    ip_hash;
    server web:8000;
}

server {
    listen      80;
    server_name 127.0.0.1;
    charset     utf-8;

    location / {
        proxy_redirect                      off;
        proxy_set_header Host               $host;
        proxy_set_header X-Real-IP          $remote_addr;
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_read_timeout          1m;
        proxy_connect_timeout       1m;
        proxy_pass                          http://nuxt:3000;
    }

    location ~* /api|admin/ {
        uwsgi_pass  django;
        include     /etc/nginx/uwsgi_params;
    }
}

server_tokens off;

uWSGI

的介绍

我们将更改设置以在Django上安装uWSGI。
将uwsgi添加到require.txt。

./dockerfiles/django_docker/requirement.txt

1
2
3
4
5
6
Django>=2.0,<3.0
djangorestframework
django-webpack-loader
django-cors-headers
mysqlclient
uwsgi #追加

编辑

docker-compose.yml。
将django启动命令从开发运行服务器切换到uwsgi。
--socket:8000 --http:8001
通过nginx访问时,WSGI为8000,
这样,从Nuxt访问时,您可以通过HTTP访问8001。

另外,从nginx容器中显示先前的配置文件。

./docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
version: '3'

services:
  db:
    image: mysql:latest
    restart: always
    container_name: mysql
    environment:
      MYSQL_ROOT_PASSWORD: test
      MYSQL_USER: test
      MYSQL_DATABASE: test
      MYSQL_PASSWORD: test
    ports:
      - 3306:3306
    expose:
      - 3306
    volumes:
      - mysqldata:/var/lib/mysql
      - ./mysql/conf.d:/etc/mysql/conf.d

  web:
    container_name: django
    build: ./dockerfiles/django_docker
    ####runserverからuwsgiコマンドに変更
    command:
      uwsgi --socket :8000 --http :8001  --module config.wsgi --py-autoreload 1 -b 32768
    ####
    volumes:
      - ./django:/code
    ports:
      - "8000:8000"
    depends_on:
      - db

  front:
    container_name: nuxt
    build: ./dockerfiles/nuxt_docker
    tty: true
    ####nuxtの起動コマンドを追加
    command: >
      bash -c 'cd front &&
      yarn dev'
    ####
    volumes:
      - ./nuxt:/code
    ports:
      - "3000:3000"

  nginx:
    image: nginx:1.13
    container_name: nginx
    ports:
      - "80:80"
    ####以下追加
    volumes:
      - ./nginx/conf:/etc/nginx/conf.d
      - ./nginx/uwsgi_params:/etc/nginx/uwsgi_params
    depends_on:
      - web
    ####

volumes:
  mysqldata:

将以下内容添加到

setting.py中的ALLOWED_HOSTS。

./django/composeexample/setting.py

1
ALLOWED_HOSTS = ["localhost","django"]

Nuxt修复

上次发布时,我使用SPA创建了它,但是我将更改挂载到异步数据以使其成为SSR。

./nuxt/front/pages/index.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//~略~

<script>
import Logo from '~/components/Logo.vue'
import axios from 'axios' //追記

export default {
  components: {
    Logo
  },

//ここから
  data() {
    return {
      dat: []
    }
  },
  async mounted(){
    const url = "/api/get_person/"
    const response = await this.$axios.get(url)
    this.dat = response.data
  }
//ここまで

//↓↓↓に変更

//ここから
  async asyncData({ $axios }){
    const url = "api/get_person/"
    const response = await $axios.get(url)  
    return { dat: response.data}
//ここまで
}
</script>
//~略~

还要修改nuxt.conf.js。
将axios baseURL更改为http:// django:8001,将browserBaseURL更改为http:// localhost。
在SSR(服务器端)期间从Nuxt容器访问API时,使用baseURL,
在浏览器(客户端)中点击API时,会使用browserBaseURL。
当使用Nuxt打API时,请直接转到Django,
对于浏览器,请转到Nginx。

./nuxt/front/nuxt.config.js

1
2
3
4
5
6
7
export default {
//~略~
  axios: {
    baseURL: "http://django:8001",
    browserBaseURL: "http://localhost",
  },
//~略~

在此状态下构建。
如果启动四个容器,则表示成功。

1
2
3
4
5
6
7
8
> docker-compose up -d --build      

> docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                                      NAMES
400297780ac2        qiita1_web          "uwsgi --socket :800…"   9 minutes ago       Up 9 minutes        0.0.0.0:8000->8000/tcp                                                     django
a7ca824f3526        nginx:1.13          "nginx -g 'daemon of…"   37 minutes ago      Up 37 minutes       0.0.0.0:80->80/tcp                                                         nginx
c96258eee9b0        qiita1_front        "docker-entrypoint.s…"   37 minutes ago      Up 37 minutes       0.0.0.0:3000->3000/tcp                                                     nuxt
58377df67b22        mysql:latest        "docker-entrypoint.s…"   37 minutes ago      Up 37 minutes       0.0.0.0:3306->3306/tcp, 33060/tcp                                          mysql

如果访问

http:// localhost并显示TOP页面,则可以通过nginx访问它。

image.png

您还可以通过

http:// localhost / api / get_person通过nginx获取API结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
> curl http://localhost/api/get_person


StatusCode        : 200
StatusDescription : OK
Content           : {"person_data": [{"id": 1, "person_name": "takashi", "person_age": 26}, {"id": 2, "pe
                    rson_name": "naoto", "person_age": 32}, {"id": 3, "person_name": "tomoko", "person_ag
                    e": 15}]}
RawContent        : HTTP/1.1 200 OK
                    Connection: keep-alive
                    Allow: GET, HEAD, OPTIONS
                    X-Frame-Options: SAMEORIGIN
                    Vary: Cookie, Origin
                    Content-Length: 179
                    Content-Type: application/json; charset=utf-8
                    Date: Fri, 08...
Forms             : {}
Headers           : {[Connection, keep-alive], [Allow, GET, HEAD, OPTIONS], [X-Frame-Options, SAMEORIGIN]
                    , [Vary, Cookie, Origin]...}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : System.__ComObject
RawContentLength  : 179                                        mysql

这样就完成了初始显示部分。

API编辑

接下来,我们将创建API部分。
由于我上次发布时仅创建了GET端点,因此我还将创建POST端点。
编辑urls.py和view.py。

./django/myapp/views.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from django.shortcuts import render
from django.views.generic import ListView

from myapp.models import Person_data

from rest_framework import status
from rest_framework.generics import ListAPIView, CreateAPIView #追加
from rest_framework.permissions import AllowAny

from .renderers import PersonJSONRenderer
from .serializers import PersonSerializer

# Create your views here.

class PersonListApiView(ListAPIView):
    model = Person_data # モデルを指定
    queryset = Person_data.objects.all()
    permission_classes = (AllowAny, )
    renderer_classes = (PersonJSONRenderer, )
    serializer_class = PersonSerializer

####以下追加
class PersonCreateApiView(CreateAPIView):
    model = Person_data
    queryset = Person_data.objects.all()
    permission_classes = (AllowAny, )
    renderer_classes = (PersonJSONRenderer, )
    serializer_class = PersonSerializer

./django/myapp/urls.py

1
2
3
4
5
6
7
8
from django.urls import path
from .views import PersonListApiView, PersonCreateApiView #追加


urlpatterns = [
    path('get_person/', PersonListApiView.as_view()),
    path('post_person/', PersonCreateApiView.as_view()), #POST追加
]

这就是添加API所需的全部。
POST并确认返回了201。
(Windows Power Shell的示例)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
> curl -Method POST -Body @{person_name="takaishi"; person_age=11;} http://localhost/api/post_person/


StatusCode        : 201
StatusDescription : Created
Content           : {"person_data": {"id": 18, "person_name": "takaishi", "person_age": 11}}  
RawContent        : HTTP/1.1 201 Created
                    Connection: keep-alive
                    Allow: POST, OPTIONS
                    X-Frame-Options: SAMEORIGIN
                    Vary: Cookie, Origin
                    Content-Length: 72
                    Content-Type: application/json; charset=utf-8
                    Date: Fri, 08 ...
Forms             : {}
Headers           : {[Connection, keep-alive], [Allow, POST, OPTIONS], [X-Frame-Options, SAMEO
                    RIGIN], [Vary, Cookie, Origin]...}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : System.__ComObject
RawContentLength  : 72

您可以通过更新TOP页面来确认已添加。

image.png

在TOP页面

上创建一个表单

创建一个简单的表单,以便您可以从网页进行POST。

./nuxt/front/pages/index.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<template>
  <div class="container">
    <div>
      <logo />
      <h1 class="title">
        front
      </h1>
      <h2 class="subtitle">
        My doozie Nuxt.js project
      </h2>
      <div class="links">
        <a
          href="https://nuxtjs.org/"
          target="_blank"
          class="button--green"
        >
          Documentation
        </a>
        <a
          href="https://github.com/nuxt/nuxt.js"
          target="_blank"
          class="button--grey"
        >
          GitHub
        </a>

        <div v-for="d in dat.person_data" :key=d.person_name align="center">
          <h2>
            {{d.person_name}} {{d.person_age}}
          </h2>
        </div>

<!-- ここから追記 -->

        <input type="text" v-model="name">
        <input type="text" v-model="age">
        <button v-on:click="post">ADD</button>

<!-- ここまで追記 -->

      </div>
    </div>
  </div>
</template>

<script>
import Logo from '~/components/Logo.vue'

export default {
  components: {
    Logo
  },

//ここから追記
  data() {
    return {
      name: '',
      age: '',
    }
  },
  methods: {
    post () {
        const url = "api/post_person/"
        axios.defaults.xsrfCookieName = 'csrftoken'
        axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"    
        axios.post(url, {person_name: this.name , person_age: this.age})
    }
  },
//ここまで追記

  async asyncData({ $axios }){
    const url = "api/get_person/"
    const response = await $axios.get(url)  
    return { dat: response.data}
  }
}
</script>
//~略~

现在,您可以从TOP页面进行POST。
您可以键入它,然后按ADD按钮发送POST。
通过刷新页面,渲染将再次运行并更新显示。

Microsoft-Edge-2020-05-09-06-14-40.gif

参考

使用Docker构建Django Nginx MySQL开发环境。
正确运行时的UWSGI设置备忘录
在EC2上尝试Django Nginx uWSGI