reactjs - 带有路由器的 ReactJS 应用程序可以托管在 S3 上并由 nginx 代理前端吗?
问题描述
我可能会扭曲一些可怕的事情,但是......我得到了一个必须提供给多个子域的 ReactJS 应用程序,所以
a.foo.bar
b.foo.bar
c.foo.bar
...
这些中的每一个都应该指向应用程序的不同实例,但我不想npm start
为每个实例运行 - 这将是一个疯狂的服务器资源量。
所以我去在 S3 上托管这些。我有一个存储桶foo.bar
,然后在其下有目录a
b
c
...并将该存储桶设置为服务静态网站。到目前为止一切顺利 - 如果我去https://s3.amazonaws.com/foo.bar/a/我会得到索引页面。然而,大多数事情往往会从那里中断,因为存在与/css/
或之类的非相对链接/somepath
- 这些中断是因为它们不够聪明,无法意识到它们是从 /foo.bar/a/ 提供服务的。另外,无论如何,我们都想要一个域。
所以现在我需要映射a.foo.bar
-> https://s3.amazonaws.com/foo.bar/a/
。我们没有使用 AWS 托管我们的域,所以我不确定是否可以使用 CloudFront 或类似的东西来处理它。按照这些思路打开解决方案,但我找不到它。
相反,我建立了一个简单的 nginx 代理。当我拥有代理时,我还添加了强制 https 和其他一些东西,形式如下:
server {
listen 443;
server_name foo.bar;
ssl on;
ssl_certificate /etc/pki/tls/certs/server.crt;
ssl_certificate_key /etc/pki/tls/certs/server.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
# Redirect (*).foo.bar to (s3bucket)/(*)
location / {
index index.html index.htm;
set $legit "0";
set $index "";
# First off, we lose the index document functionality of S3 when we
# proxy requests. So we need to add that back on to our rewrites if
# needed. This is a little dangerous, probably should find a better
# way if one exists.
if ($uri ~* "\.foo\.bar$") {
set $index "/index.html";
}
if ($uri ~* "\/$") {
set $index "index.html";
}
# If we're making a request to foo.bar (not a sub-host),
# make the request directly to "production"
if ($host ~* "^foo\.bar") {
set $legit "1";
rewrite /(.*) /foo.bar/production/$1$index break;
}
# Otherwise, take the sub-host from the request and use that for the
# redirect path
if ($host ~* "^(.*?)\.foo\.bar") {
set $legit "1";
set $subhost $1;
rewrite /(.*) /foo.bar/$subhost/$1$index break;
}
# Anything else, give them foo.bar
if ($legit = "0") {
return 302 https://foo.bar;
}
# Peform the actual proxy forward
proxy_pass https://s3.amazonaws.com/;
proxy_set_header Host s3.amazonaws.com;
proxy_set_header Referer https://s3.amazonaws.com;
proxy_set_header User-Agent $http_user_agent;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Accept-Encoding "";
proxy_set_header Accept-Language $http_accept_language;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
sub_filter google.com example.com;
sub_filter_once off;
}
}
这行得通 - 我去 a.foo.bar,我得到了我期望的索引页面,然后点击工作。但是,应用程序的一部分也执行 OAuth 样式登录,并期望浏览器被重定向回页面 /reentry?token=foo... 问题是路径仅作为 React 应用程序中的路由存在,并且该应用程序不是由像 S3 这样的静态 Web 服务器加载的,因此您只会得到 404(或 403,因为我还没有定义或转发错误页面)。
所以....所有的问题...
我可以从像 S3 这样的哑/静态服务器为 ReactJS 应用程序提供服务,并让它理解对其路由的回调吗?请记住,S3 中的索引/错误指令似乎在以我上面的方式使用代理时被丢弃。
解决方案
好的,我最初的问题有很多,但它的核心真的归结为:作为一个非 UI 人员,我如何使 OAuth 工作流与 React 应用程序一起工作?在这种情况下,回调 URL 是一个路由,如果您卸载 index.html 页面,则该路由不存在。如果您直接针对 S3,可以通过将所有错误定向到 index.html 来解决,这会重新加载路由并且回调起作用。
然而,当由 nginx 引导时,我们会丢失这个 error->index.html 路由。幸运的是,添加回来是一件非常简单的事情:
location / {
proxy_intercept_errors on;
error_page 400 403 404 500 =200 /index.html;
可能不需要所有这些状态代码 - 对于 S3,最重要的是 403。当您请求一个不存在的页面时,它会将其视为您正在尝试浏览存储桶,并为您提供返回 403 禁止而不是 404 未找到或类似的东西。因此,在这种情况下,来自 S3 的导致 403 的响应将被重定向到 /index.html,这将调用在那里加载的路由,并且对 /callback?token=... 的回调将起作用。
推荐阅读
- javascript - 在 Javascript 中检查 DIV 是否在 Window Scroll 上结束
- html - 滚动条 webkit 属性与
- 标签
- r - 为什么当我尝试制作子集数据框时我得到了很多 NA
- typescript - 当我只知道该对象键的模式时如何定义类型?
- java - 如何在 Java 中使用 XOR 开发一个OTPInputStream
- php - drupal 7中用户超时值的覆盖会话
- ios - Swift 解码错误 - (怀疑:Some Field Sometime Empty)
- python - 如何在 python django 中更新 json 数据(即使用 Id 值)?
- macos - MacOS 上的 Dart VM 嵌入 (libdart_jit.a) 产生“dyld: Symbol not found: __ZN4dart13FLAG_profilerE”
- reactjs - 无法传递 props 值?