404 Error: unable to serve static react build with django rest framework, unless I go to /index.html
404 Error: unable to serve static react build with django rest framework, unless I go to /index.html
我有一个 React 前端,我把它变成了静态文件。我用 npm run build
来制作文件夹。然后我配置了我的 Django Rest 框架:
settings.py
FRONTEND_ROOT = os.path.abspath(os.path.join(BASE_DIR, '..', 'frontend', 'build'))
urls.py
re_path(r'^(?P<path>.*)$', serve, { 'document_root': settings.FRONTEND_ROOT }),
当我到达 localhost:8000
时,我得到一个 404 页面。但是,如果我到达 localhost:8000/index.html
,那么我不会得到 404,而是反应应用程序。 css 和 html 未加载。
这是将静态反应连接到我的 Django 后端的正确方法吗?我错过了一步吗?
Django serve
更适合在开发中提供静态文件:docs.
对于开发,我只是 运行 在一个终端中反应开发服务器,在第二个终端中反应 django 开发服务器。
对于制作,您几乎没有提供静态文件的选项:
- 看看 WhiteNoise 在 django 中提供静态文件(我在某处有示例如何配置它,但现在找不到,如果您需要请告诉我),
- 上传静态react文件到S3并使用CDN服务(在AWS部署和大流量的情况下)
- 如果你想把所有东西都放在一台机器上,那么我推荐docker-compose。这是一个很好的解决方案,因为您可以使用 nginx 进行反应。此外,您可以使用 docker-compose 从 Let's Encrypt 续订 SSL 证书。这是我正在使用的选项。在我下面 docker-compose.
我正在编写有关如何使用 Django and React from scratch 构建您自己的 SaaS 应用程序的完整教程。 docker-compose 来自教程。
# docker-compose
version: '2'
services:
nginx:
restart: unless-stopped
build:
context: .
dockerfile: ./docker/nginx/Dockerfile
ports:
- 80:80
- 443:443
volumes:
- static_volume:/app/backend/server/django_static
- ./docker/nginx:/etc/nginx/conf.d
- ./docker/nginx/certbot/conf:/etc/letsencrypt
- ./docker/nginx/certbot/www:/var/www/certbot
depends_on:
- backend
certbot:
image: certbot/certbot
restart: unless-stopped
volumes:
- ./docker/nginx/certbot/conf:/etc/letsencrypt
- ./docker/nginx/certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
backend:
restart: unless-stopped
build:
context: .
dockerfile: ./docker/backend/Dockerfile
volumes:
entrypoint: /app/docker/backend/wsgi-entrypoint.sh
volumes:
- .:/app
- static_volume:/app/backend/server/django_static
ports:
- 8003:8003
expose:
- 8003
volumes:
static_volume: {}
nginx dockerfile 分两步:
- 构建反应
- 启动nginx
# nginx dockerfile
# build environment
FROM node:13.12.0-alpine as build
ADD ./frontend /app/frontend/
WORKDIR /app/frontend
RUN npm install
RUN npm run build
# production environment
FROM nginx:stable-alpine
COPY --from=build /app/frontend/build /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]
default.conf
文件
server {
listen 80;
server_name yourdomain.com;
server_tokens off;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name yourdomain.com;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
client_max_body_size 20M;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /api {
try_files $uri @proxy_api;
}
location @proxy_api {
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Url-Scheme $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://backend:8003;
}
location /django_static/ {
autoindex on;
alias /app/backend/server/django_static/;
}
}
django 的 dockerfile
FROM python:3.8.3-alpine
WORKDIR /app
ADD ./backend/requirements.txt /app/backend/
RUN pip install --upgrade pip
RUN pip install gunicorn
RUN pip install -r backend/requirements.txt
ADD ./backend /app/backend
ADD ./docker /app/docker
RUN rm -f /app/backend/server/db.sqlite3
wsgi-entrypoint.sh
#!/bin/sh
#ls -al /app/backend/server/static/client/static/js
until cd /app/backend/server
do
echo "Waiting for server volume..."
done
until ./manage.py migrate
do
echo "Waiting for db to be ready..."
sleep 2
done
ls /app/backend/server
./manage.py collectstatic --noinput
gunicorn server.wsgi --bind 0.0.0.0:8003 --workers 4 --threads 4
#./manage.py runserver 0.0.0.0:8003
init-letsencrypt.sh
来自 https://medium.com/@pentacent/nginx-and-lets-encrypt-with-docker-in-less-than-5-minutes-b4b8a60d3a71 的脚本 我强烈推荐这篇文章!
#!/bin/bash
if ! [ -x "$(command -v docker-compose)" ]; then
echo 'Error: docker-compose is not installed.' >&2
exit 1
fi
domains=(yourdomain.com www.yourdomain.com)
rsa_key_size=4096
data_path="./docker/nginx/certbot"
email="" # Adding a valid address is strongly recommended
staging=0 # Set to 1 if you're testing your setup to avoid hitting request limits
if [ -d "$data_path" ]; then
read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision
if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then
exit
fi
fi
if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then
echo "### Downloading recommended TLS parameters ..."
mkdir -p "$data_path/conf"
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf"
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem"
echo
fi
echo "### Creating dummy certificate for $domains ..."
path="/etc/letsencrypt/live/$domains"
mkdir -p "$data_path/conf/live/$domains"
docker-compose run --rm --entrypoint "\
openssl req -x509 -nodes -newkey rsa:1024 -days 1\
-keyout '$path/privkey.pem' \
-out '$path/fullchain.pem' \
-subj '/CN=localhost'" certbot
echo
echo "### Starting nginx ..."
docker-compose up --force-recreate -d nginx
echo
echo "### Deleting dummy certificate for $domains ..."
docker-compose run --rm --entrypoint "\
rm -Rf /etc/letsencrypt/live/$domains && \
rm -Rf /etc/letsencrypt/archive/$domains && \
rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot
echo
echo "### Requesting Let's Encrypt certificate for $domains ..."
#Join $domains to -d args
domain_args=""
for domain in "${domains[@]}"; do
domain_args="$domain_args -d $domain"
done
# Select appropriate email arg
case "$email" in
"") email_arg="--register-unsafely-without-email" ;;
*) email_arg="--email $email" ;;
esac
# Enable staging mode if needed
if [ $staging != "0" ]; then staging_arg="--staging"; fi
docker-compose run --rm --entrypoint "\
certbot certonly --webroot -w /var/www/certbot \
$staging_arg \
$email_arg \
$domain_args \
--rsa-key-size $rsa_key_size \
--agree-tos \
--force-renewal" certbot
echo
echo "### Reloading nginx ..."
docker-compose exec nginx nginx -s reload
我在此处粘贴了教程中的文件,因此您需要将目录结构更改为您的目录结构和域(抱歉!)。我仍在研究教程。如果您有任何问题,我很乐意提供帮助。
我有一个 React 前端,我把它变成了静态文件。我用 npm run build
来制作文件夹。然后我配置了我的 Django Rest 框架:
settings.py
FRONTEND_ROOT = os.path.abspath(os.path.join(BASE_DIR, '..', 'frontend', 'build'))
urls.py
re_path(r'^(?P<path>.*)$', serve, { 'document_root': settings.FRONTEND_ROOT }),
当我到达 localhost:8000
时,我得到一个 404 页面。但是,如果我到达 localhost:8000/index.html
,那么我不会得到 404,而是反应应用程序。 css 和 html 未加载。
这是将静态反应连接到我的 Django 后端的正确方法吗?我错过了一步吗?
Django serve
更适合在开发中提供静态文件:docs.
对于开发,我只是 运行 在一个终端中反应开发服务器,在第二个终端中反应 django 开发服务器。
对于制作,您几乎没有提供静态文件的选项:
- 看看 WhiteNoise 在 django 中提供静态文件(我在某处有示例如何配置它,但现在找不到,如果您需要请告诉我),
- 上传静态react文件到S3并使用CDN服务(在AWS部署和大流量的情况下)
- 如果你想把所有东西都放在一台机器上,那么我推荐docker-compose。这是一个很好的解决方案,因为您可以使用 nginx 进行反应。此外,您可以使用 docker-compose 从 Let's Encrypt 续订 SSL 证书。这是我正在使用的选项。在我下面 docker-compose.
我正在编写有关如何使用 Django and React from scratch 构建您自己的 SaaS 应用程序的完整教程。 docker-compose 来自教程。
# docker-compose
version: '2'
services:
nginx:
restart: unless-stopped
build:
context: .
dockerfile: ./docker/nginx/Dockerfile
ports:
- 80:80
- 443:443
volumes:
- static_volume:/app/backend/server/django_static
- ./docker/nginx:/etc/nginx/conf.d
- ./docker/nginx/certbot/conf:/etc/letsencrypt
- ./docker/nginx/certbot/www:/var/www/certbot
depends_on:
- backend
certbot:
image: certbot/certbot
restart: unless-stopped
volumes:
- ./docker/nginx/certbot/conf:/etc/letsencrypt
- ./docker/nginx/certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
backend:
restart: unless-stopped
build:
context: .
dockerfile: ./docker/backend/Dockerfile
volumes:
entrypoint: /app/docker/backend/wsgi-entrypoint.sh
volumes:
- .:/app
- static_volume:/app/backend/server/django_static
ports:
- 8003:8003
expose:
- 8003
volumes:
static_volume: {}
nginx dockerfile 分两步:
- 构建反应
- 启动nginx
# nginx dockerfile
# build environment
FROM node:13.12.0-alpine as build
ADD ./frontend /app/frontend/
WORKDIR /app/frontend
RUN npm install
RUN npm run build
# production environment
FROM nginx:stable-alpine
COPY --from=build /app/frontend/build /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]
default.conf
文件
server {
listen 80;
server_name yourdomain.com;
server_tokens off;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
server_name yourdomain.com;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
client_max_body_size 20M;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /api {
try_files $uri @proxy_api;
}
location @proxy_api {
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Url-Scheme $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://backend:8003;
}
location /django_static/ {
autoindex on;
alias /app/backend/server/django_static/;
}
}
django 的 dockerfile
FROM python:3.8.3-alpine
WORKDIR /app
ADD ./backend/requirements.txt /app/backend/
RUN pip install --upgrade pip
RUN pip install gunicorn
RUN pip install -r backend/requirements.txt
ADD ./backend /app/backend
ADD ./docker /app/docker
RUN rm -f /app/backend/server/db.sqlite3
wsgi-entrypoint.sh
#!/bin/sh
#ls -al /app/backend/server/static/client/static/js
until cd /app/backend/server
do
echo "Waiting for server volume..."
done
until ./manage.py migrate
do
echo "Waiting for db to be ready..."
sleep 2
done
ls /app/backend/server
./manage.py collectstatic --noinput
gunicorn server.wsgi --bind 0.0.0.0:8003 --workers 4 --threads 4
#./manage.py runserver 0.0.0.0:8003
init-letsencrypt.sh
来自 https://medium.com/@pentacent/nginx-and-lets-encrypt-with-docker-in-less-than-5-minutes-b4b8a60d3a71 的脚本 我强烈推荐这篇文章!
#!/bin/bash
if ! [ -x "$(command -v docker-compose)" ]; then
echo 'Error: docker-compose is not installed.' >&2
exit 1
fi
domains=(yourdomain.com www.yourdomain.com)
rsa_key_size=4096
data_path="./docker/nginx/certbot"
email="" # Adding a valid address is strongly recommended
staging=0 # Set to 1 if you're testing your setup to avoid hitting request limits
if [ -d "$data_path" ]; then
read -p "Existing data found for $domains. Continue and replace existing certificate? (y/N) " decision
if [ "$decision" != "Y" ] && [ "$decision" != "y" ]; then
exit
fi
fi
if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then
echo "### Downloading recommended TLS parameters ..."
mkdir -p "$data_path/conf"
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf"
curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem"
echo
fi
echo "### Creating dummy certificate for $domains ..."
path="/etc/letsencrypt/live/$domains"
mkdir -p "$data_path/conf/live/$domains"
docker-compose run --rm --entrypoint "\
openssl req -x509 -nodes -newkey rsa:1024 -days 1\
-keyout '$path/privkey.pem' \
-out '$path/fullchain.pem' \
-subj '/CN=localhost'" certbot
echo
echo "### Starting nginx ..."
docker-compose up --force-recreate -d nginx
echo
echo "### Deleting dummy certificate for $domains ..."
docker-compose run --rm --entrypoint "\
rm -Rf /etc/letsencrypt/live/$domains && \
rm -Rf /etc/letsencrypt/archive/$domains && \
rm -Rf /etc/letsencrypt/renewal/$domains.conf" certbot
echo
echo "### Requesting Let's Encrypt certificate for $domains ..."
#Join $domains to -d args
domain_args=""
for domain in "${domains[@]}"; do
domain_args="$domain_args -d $domain"
done
# Select appropriate email arg
case "$email" in
"") email_arg="--register-unsafely-without-email" ;;
*) email_arg="--email $email" ;;
esac
# Enable staging mode if needed
if [ $staging != "0" ]; then staging_arg="--staging"; fi
docker-compose run --rm --entrypoint "\
certbot certonly --webroot -w /var/www/certbot \
$staging_arg \
$email_arg \
$domain_args \
--rsa-key-size $rsa_key_size \
--agree-tos \
--force-renewal" certbot
echo
echo "### Reloading nginx ..."
docker-compose exec nginx nginx -s reload
我在此处粘贴了教程中的文件,因此您需要将目录结构更改为您的目录结构和域(抱歉!)。我仍在研究教程。如果您有任何问题,我很乐意提供帮助。