使用 nginx 为 single-page-app 提供静态资产
Serving static assets for a single-page-app with nginx
我正在尝试弄清楚如何让 nginx 为静态资产提供服务,退回到 index.html,然后转到 API。
目前,我所做的只是根路由 /
和 API 转发。
这是我追求的行为:
GET / -> nginx sends s3/index.html (current)
* /api -> nginx proxies to the puma server (current)
# Yet to figure out (and the reason for this question)
GET /sub-route -> nginx sends s3/index.html, and routing is handled by the js framework
GET *.css|.js|etc -> nginx forwards to the s3 bucket (all relative to index.html)
这是我的 nginx.conf(里面有一些模板,因为(作为部署过程的一部分)我这样做:
envsubst '$S3_BUCKET:$NGINX_PORT' < /app/deployment/nginx.template.conf > /app/deployment/nginx.conf
pid /app/tmp/nginx.pid;
events { }
http {
upstream puma {
server unix:///app/sockets/puma.sock;
}
server {
listen ${NGINX_PORT} default_server deferred;
server_name aeonvera.com;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
root /app/public;
access_log /app/log/nginx.access.log;
error_log /app/log/nginx.error.log info;
client_max_body_size 20M;
keepalive_timeout 5;
location ~ ^/api {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://puma;
}
# Send all other requests to the index.html
# stored up on s3
location / {
# tell all URLs to go to the index.html
# I got an error with this about having proxy_pass within a location...?
# location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2|woff|ttf)$ {
# proxy_pass "https://s3.amazonaws.com/${S3_BUCKET}/ember/"
#
# gzip_static on;
# expires max;
# add_header Cache-Control public;
# }
# Don't know what this does
rewrite ^([^.]*[^/])$ / permanent;
# only ever GET these resources
limit_except GET {
deny all;
}
# use google as dns
resolver 8.8.8.8;
proxy_http_version 1.1;
proxy_set_header Host 's3.amazonaws.com';
proxy_set_header Authorization '';
# avoid passing along amazon headers
proxy_hide_header x-amz-id-2;
proxy_hide_header x-amz-request-id;
proxy_hide_header x-amz-delete-marker;
proxy_hide_header x-amz-version-id;
# cookies are useless on these static, public resources
proxy_hide_header Set-Cookie;
proxy_ignore_headers "Set-Cookie";
proxy_set_header cookie "";
proxy_buffering off;
# s3 replies with 403 if an object is inaccessible; essentially not found
proxy_intercept_errors on;
# error_page 500 502 503 504 /500.html;
# the actual static files
proxy_pass "https://s3.amazonaws.com/${S3_BUCKET}/ember/index.html";
}
}
}
更新 1
我在上面添加了这个location /
location ~ ^/(assets|fonts) {
rewrite (.*) break;
proxy_pass "https://s3.amazonaws.com/${S3_BUCKET}/ember";
gzip_static on;
expires max;
add_header Cache-Control public;
}
但是报错:
nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block in /app/deployment/nginx.conf:53
此更改背后的想法是,由于我的所有资产都在已知位置,我可以告诉 nginx 代理到该位置,然后为我的 location /
更新 2
我想也许我可以 re-write url /dashboard
,
这样 nginx 就会 proxy_pass index.html。没有成功。
rewrite ^/(.*) / break;
proxy_pass "https://s3.amazonaws.com/${S3_BUCKET}/ember/index.html";
这只是重定向到 s3 的营销页面
Content-Length:0
Content-Type:text/plain; charset=utf-8
Date:Thu, 08 Feb 2018 13:22:49 GMT
Location:https://aws.amazon.com/s3/
Server:nginx/1.12.0
回复Headers^
我认为我想出来了,但是如果有人能验证的话会非常有帮助,因为我对nginx还是很陌生。
location / {
# ...
proxy_set_header Host 's3.amazonaws.com';
# ...
rewrite ^/(.*) /${S3_BUCKET}/ember/index.html break;
proxy_pass "https://s3.amazonaws.com/${S3_BUCKET}/ember/index.html";
}
Host
header 在这里很重要,因为没有它,重写将改变用户浏览器中的 URL(我们不想这样做,因为很可能会扰乱 SPA 的路由。
我正在尝试弄清楚如何让 nginx 为静态资产提供服务,退回到 index.html,然后转到 API。
目前,我所做的只是根路由 /
和 API 转发。
这是我追求的行为:
GET / -> nginx sends s3/index.html (current)
* /api -> nginx proxies to the puma server (current)
# Yet to figure out (and the reason for this question)
GET /sub-route -> nginx sends s3/index.html, and routing is handled by the js framework
GET *.css|.js|etc -> nginx forwards to the s3 bucket (all relative to index.html)
这是我的 nginx.conf(里面有一些模板,因为(作为部署过程的一部分)我这样做:
envsubst '$S3_BUCKET:$NGINX_PORT' < /app/deployment/nginx.template.conf > /app/deployment/nginx.conf
pid /app/tmp/nginx.pid;
events { }
http {
upstream puma {
server unix:///app/sockets/puma.sock;
}
server {
listen ${NGINX_PORT} default_server deferred;
server_name aeonvera.com;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
root /app/public;
access_log /app/log/nginx.access.log;
error_log /app/log/nginx.error.log info;
client_max_body_size 20M;
keepalive_timeout 5;
location ~ ^/api {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://puma;
}
# Send all other requests to the index.html
# stored up on s3
location / {
# tell all URLs to go to the index.html
# I got an error with this about having proxy_pass within a location...?
# location ~* \.(?:ico|css|js|gif|jpe?g|png|woff2|woff|ttf)$ {
# proxy_pass "https://s3.amazonaws.com/${S3_BUCKET}/ember/"
#
# gzip_static on;
# expires max;
# add_header Cache-Control public;
# }
# Don't know what this does
rewrite ^([^.]*[^/])$ / permanent;
# only ever GET these resources
limit_except GET {
deny all;
}
# use google as dns
resolver 8.8.8.8;
proxy_http_version 1.1;
proxy_set_header Host 's3.amazonaws.com';
proxy_set_header Authorization '';
# avoid passing along amazon headers
proxy_hide_header x-amz-id-2;
proxy_hide_header x-amz-request-id;
proxy_hide_header x-amz-delete-marker;
proxy_hide_header x-amz-version-id;
# cookies are useless on these static, public resources
proxy_hide_header Set-Cookie;
proxy_ignore_headers "Set-Cookie";
proxy_set_header cookie "";
proxy_buffering off;
# s3 replies with 403 if an object is inaccessible; essentially not found
proxy_intercept_errors on;
# error_page 500 502 503 504 /500.html;
# the actual static files
proxy_pass "https://s3.amazonaws.com/${S3_BUCKET}/ember/index.html";
}
}
}
更新 1
我在上面添加了这个location /
location ~ ^/(assets|fonts) {
rewrite (.*) break;
proxy_pass "https://s3.amazonaws.com/${S3_BUCKET}/ember";
gzip_static on;
expires max;
add_header Cache-Control public;
}
但是报错:
nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block in /app/deployment/nginx.conf:53
此更改背后的想法是,由于我的所有资产都在已知位置,我可以告诉 nginx 代理到该位置,然后为我的 location /
更新 2
我想也许我可以 re-write url /dashboard
,
这样 nginx 就会 proxy_pass index.html。没有成功。
rewrite ^/(.*) / break;
proxy_pass "https://s3.amazonaws.com/${S3_BUCKET}/ember/index.html";
这只是重定向到 s3 的营销页面
Content-Length:0
Content-Type:text/plain; charset=utf-8
Date:Thu, 08 Feb 2018 13:22:49 GMT
Location:https://aws.amazon.com/s3/
Server:nginx/1.12.0
回复Headers^
我认为我想出来了,但是如果有人能验证的话会非常有帮助,因为我对nginx还是很陌生。
location / {
# ...
proxy_set_header Host 's3.amazonaws.com';
# ...
rewrite ^/(.*) /${S3_BUCKET}/ember/index.html break;
proxy_pass "https://s3.amazonaws.com/${S3_BUCKET}/ember/index.html";
}
Host
header 在这里很重要,因为没有它,重写将改变用户浏览器中的 URL(我们不想这样做,因为很可能会扰乱 SPA 的路由。