ChatGPT解决这个技术问题 Extra ChatGPT

S3 静态网站托管将所有路径路由到 Index.html

我正在使用 S3 托管将使用 HTML5 pushStates 的 javascript 应用程序。问题是如果用户为任何 URL 添加书签,它不会解决任何问题。我需要的是能够接受所有 url 请求并在我的 S3 存储桶中提供根 index.html,而不仅仅是进行完全重定向。然后我的 javascript 应用程序可以解析 URL 并提供正确的页面。

有没有办法告诉 S3 为所有 URL 请求提供 index.html 而不是重定向?这类似于通过提供单个 index.html 来设置 apache 来处理所有传入请求,如本示例中所示:https://stackoverflow.com/a/10647521/1762614。我真的很想避免仅仅为了处理这些路由而运行 Web 服务器。从 S3 做所有事情都非常吸引人。

你找到解决方案了吗?
如果您在 2020 年后到达这里,请务必按 Active 对答案进行排序。如今,所有旧答案都已过时。

l
lenaten

在 CloudFront 的帮助下,无需 url hack 即可轻松解决。

创建 S3 存储桶,例如:react

使用以下设置创建 CloudFront 分配: 默认根对象:index.html 源域名:S3 存储桶域,例如:react.s3.amazonaws.com

默认根对象:index.html

Origin Domain Name:S3存储桶域,例如:react.s3.amazonaws.com

转到错误页面选项卡,单击创建自定义错误响应:HTTP 错误代码:403:禁止(404:未找到,如果是 S3 静态网站)自定义错误响应:是响应页面路径:/index.html HTTP 响应代码: 200:确定点击创建

HTTP 错误代码:403:禁止(404:未找到,如果是 S3 静态网站)

自定义错误响应:是

响应页面路径:/index.html

HTTP 响应代码:200:确定

点击创建


谢谢。迄今为止最好的答案。
这对我来说就像一个魅力,只有我需要的自定义错误代码是 404,而不是 403
有点 hack,但效果很好 :) 如果 CloudFront 让我们将一系列路径映射到 S3 文件(没有重定向),那就太好了。
@NathanielMaman,因为您的 cf 发行版中可能有两个来源。 .com/app (s3) 和 .com/auth (ec2/whatever)。错误响应是顶级的,因此无法从 /auth 或其他任何地方分辨 s3 403 和 403 之间的差异。私有的、仅限预览版的 Lambda@Edge 是解决方案,是 mod_rewrite 的荒谬解决方案。
这对我不起作用。此解决方案始终重定向到主页而不是正确的页面...
M
Mario Petrovic

我能够让它工作的方式如下:

在您的域的 S3 控制台的编辑重定向规则部分,添加以下规则:

<RoutingRules>
  <RoutingRule>
    <Condition>
      <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
    </Condition>
    <Redirect>
      <HostName>yourdomainname.com</HostName>
      <ReplaceKeyPrefixWith>#!/</ReplaceKeyPrefixWith>
    </Redirect>
  </RoutingRule>
</RoutingRules>

这会将导致找不到 404 的所有路径重定向到您的根域,并使用该路径的 hash-bang 版本。因此,如果 /posts 中没有文件,http://yourdomainname.com/posts 将重定向到 http://yourdomainname.com/#!/posts

然而,要使用 HTML5 pushStates,我们需要接受这个请求并根据 hash-bang 路径手动建立正确的 pushState。因此,将其添加到 index.html 文件的顶部:

<script>
  history.pushState({}, "entry page", location.hash.substring(1));
</script>

这会抓取哈希并将其转换为 HTML5 pushState。从此时起,您可以使用 pushStates 在您的应用程序中设置非散列路径。


这个解决方案效果很好!事实上,如果配置了 html 模式,angularjs 会自动执行历史 pushState。
如果您的 url 中包含 GET 参数,这将在旧版本的 IE 中失败,对吗?你如何解决这个问题?
谢谢!稍微调整一下,这对我来说在骨干上效果很好。我添加了对旧浏览器的检查:<script language="javascript"> if (typeof(window.history.pushState) == 'function') { window.history.pushState(null, "Site Name", window.location.hash.substring(2)); } else { window.location.hash = window.location.hash.substring(2); } </script>
使用 HTML5 pushStates 和 <ReplaceKeyPrefixWith>#/</ReplaceKeyPrefixWith> 的解决方案成功地完成了 react-router
它在 safari 中不起作用,并且是部署策略的一个大问题。编写一个小 js 来重定向是一种破旧的方法。此外,重定向的数量也是一个问题。我试图弄清楚是否有办法让所有 S3 url 始终指向 index.html。
m
moha297

其他人提到的基于 S3/Redirect 的方法几乎没有问题。

当您的应用程序的路径被解析时,会发生多次重定向。例如: www.myapp.com/path/for/test 被重定向为 www.myapp.com/#/path/for/test 由于“#”的出现和消失,url 栏中会闪烁你的 SPA 框架。 seo 受到影响是因为 - '嘿!它的谷歌强迫他对你的应用程序的重定向 Safari 支持进行了折腾。

解决方案是:

确保您已为您的网站配置了索引路由。主要是 index.html 从 S3 配置中删除路由规则 在 S3 存储桶前面放置一个 Cloudfront。为您的 Cloudfront 实例配置错误页面规则。在错误规则中指定: Http 错误代码:404(和 403 或其他错误根据需要) 错误缓存最小 TTL(秒):0 自定义响应:是 响应页面路径:/index.html HTTP 响应代码:200 用于 SEO 需要+ 确保您的 index.html 没有缓存,请执行以下操作:配置 EC2 实例并设置 nginx 服务器。为您的 EC2 实例分配一个公共 IP。创建一个将您创建的 EC2 实例作为实例的 ELB 您应该能够将 ELB 分配给您的 DNS。现在,配置您的 nginx 服务器以执行以下操作:代理_将所有请求传递给您的 CDN(仅用于 index.html,直接从您的云端提供其他资产)和搜索机器人,按照 Prerender.io 等服务的规定重定向流量

我可以提供有关 nginx 设置的更多详细信息,只需留言即可。已经学会了它的艰难方式。

一旦云端分发更新。使您的云端缓存失效一次以进入原始模式。在浏览器中点击 url,一切都应该很好。


由于当文件不存在时 S3 以 403 Forbidden 响应,我认为上面的步骤 4 也必须为 Http 错误代码 403 重复
对我来说,这是导致预期(接受)行为的唯一答案
@moha297 还有一个问题。为什么不直接从 EC2 实例本身服务器 index.html 而不是代理它?
@moha297 在第 5 点中,您是否基本上将您的站点配置为从 nginx 获取,然后从 CDN 代理(index.html 和爬虫请求除外)?如果是这样的话,你不会失去 CDN 边缘服务器的好处吗?
@moha297 你能解释一下这个评论吗:“你不应该从 CDN 提供 index.html”?我没有看到使用 CloudFront 从 S3 提供 index.html 的问题。
C
Community

这是切题的,但对于那些使用具有 (HTML5) 浏览器历史记录的 Rackt's React Router library 并希望在 S3 上托管的人来说,这是一个提示。

假设用户在您的 S3 托管的静态网站上访问 /foo/bear。给定 David's earlier suggestion,重定向规则会将它们发送到 /#/foo/bear。如果您的应用程序是使用浏览器历史记录构建的,那么这不会有什么好处。但是此时您的应用程序已加载,它现在可以操作历史记录。

在我们的项目中包含 Rackt history(另请参阅 React Router 项目中的 Using Custom Histories),您可以添加一个了解哈希历史路径的侦听器并根据需要替换路径,如下例所示:

import ReactDOM from 'react-dom';

/* Application-specific details. */
const route = {};

import { Router, useRouterHistory } from 'react-router';
import { createHistory } from 'history';

const history = useRouterHistory(createHistory)();

history.listen(function (location) {
  const path = (/#(\/.*)$/.exec(location.hash) || [])[1];
  if (path) history.replace(path);
});

ReactDOM.render(
  <Router history={history} routes={route}/>,
  document.body.appendChild(document.createElement('div'))
);

回顾一下:

David 的 S3 重定向规则会将 /foo/bear 定向到 /#/foo/bear。您的应用程序将加载。历史监听器将检测 #/foo/bear 历史记法。并用正确的路径替换历史。

Link tags 将按预期工作,所有其他浏览器历史记录功能也一样。我注意到的唯一缺点是初始请求时发生的插页式重定向。

这受到 a solution for AngularJS 的启发,我怀疑它可以很容易地适应任何应用程序。


这帮助了我迈克尔,谢谢!您可能想从历史记录中更改您的参考,并只使用 BrowserHistory。即browserHistory.listen
别客气!乐意效劳。另外,同意,对于这个特定的用例,我更新了代码片段以解决来自 React Router 的弃用警告。
随着 react-router v3.0.0 的发布,这不起作用,因为 react-router v3.0.0 使用 History v3.0.0
知道如何防止 history.listen 无限调用循环吗?由我猜的替换路径引起的。
C
Community

我看到了这个问题的 4 个解决方案。前三个已经包含在答案中,最后一个是我的贡献。

将错误文档设置为 index.html。问题:响应正文将是正确的,但状态码将是 404,这会伤害 SEO。设置重定向规则。问题:URL 被 #!加载时页面闪烁。配置 CloudFront。问题:所有页面都将从源返回 404,因此您需要选择是否不缓存任何内容(建议的 TTL 0)或者是否缓存并在更新站点时遇到问题。预渲染所有页面。问题:预渲染页面的额外工作,特别是当页面频繁更改时。例如,新闻网站。

我的建议是使用选项 4。如果您预呈现所有页面,则预期页面不会出现 404 错误。页面将正常加载,框架将控制并正常充当 SPA。您还可以设置错误文档以显示通用 error.html 页面和重定向规则以将 404 错误重定向到 404.html 页面(没有 hashbang)。

关于 403 Forbidden 错误,我根本不让它们发生。在我的应用程序中,我认为主机存储桶中的所有文件都是公共的,我使用具有读取权限的所有人选项来设置它。如果您的站点有私有页面,那么让用户查看 HTML 布局应该不是问题。您需要保护的是数据,这是在后端完成的。

此外,如果您有私人资产,例如用户照片,您可以将它们保存在另一个存储桶中。因为私有资产需要与数据一样的关注,并且无法与用于托管应用程序的资产文件进行比较。


并且您的网站有一个很好的示例,可以使用 with 为所有页面进行预渲染。 zanon.io/posts/… .- 谢谢
这第四种方法是否解决了用户重新加载 pushState URL 的问题?它可以很好地处理导航,但在重新加载时,它仍然会到达服务器。
@Alpha,我不确定我是否正确理解了您的问题,但是在重新加载时,它将充当新请求。 S3 将收到请求并再次返回预呈现的页面。在这种情况下没有服务器。
@Zanon 啊,我想我明白了。我认为这是为了缓存预渲染页面并避免使用 S3 不存在的资源。这会遗漏具有动态元素的路线,对吗?
@Zanon 我终于明白了——谢谢!是的,这就是我的意思。 :)
S
Sergey Kandaurov

使从 Amazon S3 提供的 Angular 2+ 应用程序和直接 URL 工作的最简单解决方案是在 S3 存储桶配置中将 index.html 指定为索引和错误文档。

https://i.stack.imgur.com/OIGS3.jpg


这与 this heavily downvoted answer 的答案相同。它工作正常,但仅适用于响应的 body。状态码将是 404,它会伤害 SEO。
因为这仅适用于 body,如果您在 head 中导入了任何脚本,当您直接点击您网站上的任何子路由时,它们将不起作用
M
Mario Petrovic

我今天遇到了同样的问题,但是@Mark-Nutter 的解决方案不完整,无法从我的 angularjs 应用程序中删除 hashbang。

实际上,您必须转到编辑权限,单击添加更多权限,然后将您的存储桶上的正确列表添加到每个人。使用此配置,AWS S3 现在将能够返回 404 错误,然后重定向规则将正确捕获该情况。

https://i.stack.imgur.com/VkJVF.png

然后你可以去编辑重定向规则并添加这个规则:

<RoutingRules>
    <RoutingRule>
        <Condition>
            <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
        </Condition>
        <Redirect>
            <HostName>subdomain.domain.fr</HostName>
            <ReplaceKeyPrefixWith>#!/</ReplaceKeyPrefixWith>
        </Redirect>
    </RoutingRule>
</RoutingRules>

如果您不将 hashbang 方法用于 SEO,您可以在此处将 HostName subdomain.domain.fr 替换为您的域和 KeyPrefix #!/。

当然,所有这些只有在你的 Angular 应用程序中已经设置了 html5mode 时才会起作用。

$locationProvider.html5Mode(true).hashPrefix('!');

我唯一的问题是你有一个hashbang,你没有像nginx规则这样的东西。用户在页面上并刷新:/products/1 -> #!/products/1 -> /products/1
我认为您应该为 403 错误添加规则,而不是向所有人授予列表权限。
M
Mario Petrovic

您现在可以使用 Lambda@Edge 来重写路径

这是一个有效的 lambda@Edge 函数:

创建一个新的 Lambda 函数,但使用预先存在的蓝图之一而不是空白函数。搜索“cloudfront”并从搜索结果中选择 cloudfront-response-generation。创建函数后,将内容替换为以下内容。我还不得不将节点运行时更改为 10.x,因为在撰写本文时 cloudfront 不支持节点 12。

'use strict';
exports.handler = (event, context, callback) => {
    
    // Extract the request from the CloudFront event that is sent to Lambda@Edge 
    var request = event.Records[0].cf.request;

    // Extract the URI from the request
    var olduri = request.uri;

    // Match any '/' that occurs at the end of a URI. Replace it with a default index
    var newuri = olduri.replace(/\/$/, '\/index.html');
    
    // Log the URI as received by CloudFront and the new URI to be used to fetch from origin
    console.log("Old URI: " + olduri);
    console.log("New URI: " + newuri);
    
    // Replace the received URI with the URI that includes the index page
    request.uri = newuri;

    return callback(null, request);
};

https://i.stack.imgur.com/jTmVE.png

完整教程:https://aws.amazon.com/blogs/compute/implementing-default-directory-indexes-in-amazon-s3-backed-amazon-cloudfront-origins-using-lambdaedge/


您的代码示例只漏掉了一行:return callback(null, request);
这是 2020 年以后的正确答案
我的 lambda@Edge 从未被调用,我需要额外的角色权限吗?
这是正确的方法。只是替换的正则表达式我认为应该是这样的: var newuri = olduri.replace(/\/.+$/, '\/index.html');
我在下面提供了一个使用 Cloudfront Functions(AWS 免费套餐的一部分)的答案。
M
Mario Petrovic

正在寻找同样的问题。我最终混合使用了上述建议的解决方案。

首先,我有一个包含多个文件夹的 s3 存储桶,每个文件夹代表一个 react/redux 网站。我还使用云端缓存失效。

所以我不得不使用路由规则来支持 404 并将它们重定向到哈希配置:

<RoutingRules>
    <RoutingRule>
        <Condition>
            <KeyPrefixEquals>website1/</KeyPrefixEquals>
            <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
        </Condition>
        <Redirect>
            <Protocol>https</Protocol>
            <HostName>my.host.com</HostName>
            <ReplaceKeyPrefixWith>website1#</ReplaceKeyPrefixWith>
        </Redirect>
    </RoutingRule>
    <RoutingRule>
        <Condition>
            <KeyPrefixEquals>website2/</KeyPrefixEquals>
            <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
        </Condition>
        <Redirect>
            <Protocol>https</Protocol>
            <HostName>my.host.com</HostName>
            <ReplaceKeyPrefixWith>website2#</ReplaceKeyPrefixWith>
        </Redirect>
    </RoutingRule>
    <RoutingRule>
        <Condition>
            <KeyPrefixEquals>website3/</KeyPrefixEquals>
            <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
        </Condition>
        <Redirect>
            <Protocol>https</Protocol>
            <HostName>my.host.com</HostName>
            <ReplaceKeyPrefixWith>website3#</ReplaceKeyPrefixWith>
        </Redirect>
    </RoutingRule>
</RoutingRules>

在我的 js 代码中,我需要使用 react-router 的 baseName 配置来处理它。首先,确保您的依赖项是可互操作的,我安装了与 react-router==3.0.1 不兼容的 history==4.0.0

我的依赖是:

“历史”:“3.2.0”,

“反应”:“15.4.1”,

"react-redux": "4.4.6",

“反应路由器”:“3.0.1”,

"react-router-redux": "4.0.7",

我创建了一个用于加载历史记录的 history.js 文件:

import {useRouterHistory} from 'react-router';
import createBrowserHistory from 'history/lib/createBrowserHistory';

export const browserHistory = useRouterHistory(createBrowserHistory)({
    basename: '/website1/',
});

browserHistory.listen((location) => {
    const path = (/#(.*)$/.exec(location.hash) || [])[1];
    if (path) {
        browserHistory.replace(path);
    }
});

export default browserHistory;

这段代码允许使用哈希处理服务器发送的 404,并在历史记录中替换它们以加载我们的路由。

您现在可以使用此文件来配置您的商店和您的根文件。

import {routerMiddleware} from 'react-router-redux';
import {applyMiddleware, compose} from 'redux';

import rootSaga from '../sagas';
import rootReducer from '../reducers';

import {createInjectSagasStore, sagaMiddleware} from './redux-sagas-injector';

import {browserHistory} from '../history';

export default function configureStore(initialState) {
    const enhancers = [
        applyMiddleware(
            sagaMiddleware,
            routerMiddleware(browserHistory),
        )];

    return createInjectSagasStore(rootReducer, rootSaga, initialState, compose(...enhancers));
}
import React, {PropTypes} from 'react';
import {Provider} from 'react-redux';
import {Router} from 'react-router';
import {syncHistoryWithStore} from 'react-router-redux';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import variables from '!!sass-variable-loader!../../../css/variables/variables.prod.scss';
import routesFactory from '../routes';
import {browserHistory} from '../history';

const muiTheme = getMuiTheme({
    palette: {
        primary1Color: variables.baseColor,
    },
});

const Root = ({store}) => {
    const history = syncHistoryWithStore(browserHistory, store);
    const routes = routesFactory(store);

    return (
        <Provider {...{store}}>
            <MuiThemeProvider muiTheme={muiTheme}>
                <Router {...{history, routes}} />
            </MuiThemeProvider>
        </Provider>
    );
};

Root.propTypes = {
    store: PropTypes.shape({}).isRequired,
};

export default Root;

希望能帮助到你。你会注意到这个配置我使用 redux 注入器和一个自制的 sagas 注入器来通过路由异步加载 javascript。不要介意这些行。


c
claptimes

与使用 Lambda@Edge 的另一个 answer 类似,您可以使用 Cloudfront Functions(自 2021 年 8 月起,它已成为 free tier 的一部分)。

我的网址结构是这样的:

example.com - 托管在 S3 上的 React SPA

example.com/blog - 托管在 EC2 上的博客

由于我将博客托管在与 SPA 相同的域中,因此我无法使用使用默认错误页面的 Cloudfront 403/404 错误页面的建议答案。

我对 Cloudfront 的设置是:

设置两个来源(S3 和我的 EC2 实例通过 Elastic ALB) 设置两个行为:/blog 默认 (*) 创建 Cloudfront 函数 将 Cloudfront 函数设置为默认 (*) 行为的“查看器请求”

我正在使用基于 AWS example 的 Cloudfront 函数。这可能不适用于所有情况,但我的 React 应用程序的 URL 结构不包含任何 .

function handler(event) {
    var request = event.request;
    var uri = request.uri;
       
    // If the request is not for an asset (js, png, etc), render the index.html
    if (!uri.includes('.')) {
        request.uri = '/index.html';
    }
      
    return request;
}

编辑 2022 年 6 月

我已将我的功能更新为:

function handler(event) {
    var request = event.request;
    var uri = request.uri;
    
    // Check whether the URI is missing a file name.
    if (uri.endsWith('/')) {
        request.uri += 'index.html';
    } 
    // Check whether the URI is missing a file extension.
    else if (!uri.includes('.')) {
        request.uri += '/index.html';
    }

    return request;
}

关于免费层的非常好的信息。每月 200 万次免费 Cloudfront 函数调用,0 次免费 Lambda@Edge 调用。
L
Lordd Lazaro

转到您的存储桶的静态网站托管设置并将错误文档设置为 index.html。


你救了我的一天!非常感谢!
这些天你真的不应该使用 S3 的内置静态网站托管。所有新存储桶都应配置为启用阻止公共访问。为此使用 Cloudfront。
同意@forresthopkinsa 的评论。
同意@forresthopkinsa 的评论。将“错误文档”设置为“index.html”很容易并解决了上述问题,但效率低下。看看这篇 AWS 博客文章:aws.amazon.com/blogs/networking-and-content-delivery/… 注意:链接与所问的问题无关
A
Andrew Arnautov

因为问题仍然存在,但我提出了另一个解决方案。我的情况是,我想在合并之前将所有拉取请求自动部署到 s3 进行测试,使它们可以在 [mydomain]/pull-requests/[pr number]/ 上访问(例如 www.example.com/pull-requests/822/ )

据我所知,非 s3 规则场景将允许使用 html5 路由在一个存储桶中拥有多个项目,因此虽然上面大多数投票的建议适用于根文件夹中的项目,但不适用于自己的子文件夹中的多个项目。

所以我将我的域指向我的服务器,在该服务器上遵循 nginx 配置完成了这项工作

location /pull-requests/ {
    try_files $uri @get_files;
}
location @get_files {
    rewrite ^\/pull-requests\/(.*) /$1 break;
    proxy_pass http://<your-amazon-bucket-url>;
    proxy_intercept_errors on;
    recursive_error_pages on;
    error_page 404 = @get_routes;
}

location @get_routes {
    rewrite ^\/(\w+)\/(.+) /$1/ break;
    proxy_pass http://<your-amazon-bucket-url>;
    proxy_intercept_errors on;
    recursive_error_pages on;
    error_page 404 = @not_found;
}

location @not_found {
    return 404;
}

它尝试获取文件,如果未找到,则假定它是 html5 路由并尝试。如果您有未找到路线的 404 角度页面,您将永远无法到达 @not_found 并返回 404 角度页面而不是未找到文件,这可以通过 @get_routes 中的某些 if 规则或其他内容来修复。

我不得不说我在 nginx 配置和使用正则表达式方面感觉不太舒服,我通过一些试验和错误得到了这个工作,所以虽然这个工作我相信还有改进的空间,请分享你的想法.

注意:如果您在 S3 配置中有 s3 重定向规则,请删除它们。

顺便说一句,在 Safari 中工作


嗨..感谢您的解决方案...您将这个用于 s3 部署的 nginx conf 文件放在哪里。它与我需要创建 .exextensions 文件夹并将其放入 proxy.config 文件的弹性 beanstalk 相同吗?
@user3124360 不确定弹性 beanstack,但在我的情况下,我将我的域名指向 ec2 实例并在那里进行 nginx 配置。所以请求去 CLIENT -> DNS -> EC2 -> S3 -> CLIENT。
是的,我正在做一些非常相似的事情...在这里使用 nginx 配置 github.com/davezuko/react-redux-starter-kit/issues/1099...感谢您发布您的 conf 文件..我了解如何开发此 EC2 ->现在 S3 连接
Y
Yaro

如果您在这里寻找与 React Router 和 AWS Amplify 控制台一起使用的解决方案 - 您已经知道您不能直接使用 CloudFront 重定向规则,因为 Amplify 控制台不会为应用程序公开 CloudFront 分发。

但是,解决方案非常简单 - 您只需在 Amplify 控制台中添加重定向/重写规则,如下所示:

https://i.stack.imgur.com/DuJ0E.png

有关更多信息,请参阅以下链接(以及屏幕截图中的复制友好规则):

https://docs.aws.amazon.com/amplify/latest/userguide/redirects.html#redirects-for-single-page-web-apps-spa

https://github.com/aws-amplify/amplify-console/issues/83


S
Sandeep Dixit

大多数提议的解决方案的问题,尤其是最流行的答案,是您永远不会收到不存在的后端资源的 404 错误。如果你想继续得到404,参考这个解决方案

我为所有路由添加了根路径(这是此解决方案的新功能),例如,我所有的路由路径都以相同的前端根目录开头...代替路径 /foo/baz、/foo2/baz 我现在有了 /root /foo/baz , /root/foo2/baz 路径。前端根目录的选择不会与后端的任何真实文件夹或路径发生冲突。现在我可以使用这个根在任何地方创建简单的重定向规则,我喜欢。我所有的重定向更改都只会影响这条路径,其他一切都会像以前一样。

这是我在 s3 存储桶中添加的重定向规则

[
    {
        "Condition": {
            "HttpErrorCodeReturnedEquals": "404",
            "KeyPrefixEquals": "root/"
        },
        "Redirect": {
            "HostName": "mydomain.com",
            "ReplaceKeyPrefixWith": "#/"
        }
    }
]

甚至跟随

[
        {
            "Condition": {
               
                "KeyPrefixEquals": "root/"
            },
            "Redirect": {
                "HostName": "mydomain.com",
                "ReplaceKeyPrefixWith": "#/"
            }
        }
    ]

在此之后,/root/foo/baz 被重定向到 /#/foo/baz,并且页面在首页加载而没有错误。

安装 Vue 应用程序后,我在加载时添加了以下代码。它会将我的应用程序带到所需的路线。您可以根据 Angular 或您使用的任何内容更改 router.push 部分。

if(location.href.includes("#"))
{
  let currentRoute = location.href.split("#")[1];

  router.push({ path: `/root${currentRoute}` })
}

即使您不在 s3 级别使用重定向,在您可能喜欢的任何其他重定向中,对所有路由都有一个单一的基础也很方便。它帮助后端识别不是对真正后端资源的请求,前端应用程序将能够处理它。


m
mcont

此处未提及的解决方案是使用 CloudFront Functions 将请求 URI 重写为 viewer request 上的 index.html

function handler(event) {
    var request = event.request;
    request.uri = '/index.html';
    return request;
}

E
Ed Thomas

我自己也在寻找这个问题的答案。 S3 似乎只支持重定向,您不能只重写 URL 并默默地返回不同的资源。我正在考虑使用我的构建脚本在所有必需的路径位置简单地复制我的 index.html。也许这也对你有用。


我也想过为每个路径生成索引文件,但很难拥有像 example.com/groups/5/show 这样的动态路径。如果您看到我对这个问题的回答,我相信这在很大程度上解决了问题。这有点骇人听闻,但至少它有效。
最好部署在 nginx 服务器后面并为所有传入的 url 返回 index.html。我已经通过 ember 应用程序的 heroku 部署成功地做到了这一点。
M
Meester Over

只是提出一个非常简单的答案。如果您在 S3 上托管,只需对路由器使用哈希定位策略。

export const AppRoutingModule: ModuleWithProviders = RouterModule.forRoot(routes, { useHash: true, scrollPositionRestoration: 'enabled' });