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

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


当前回答

这是一个非常简单的答案。如果您在S3上托管,则只需为路由器使用散列位置策略。

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

其他回答

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

然而,解决方案非常简单-你只需要在Amplify控制台中添加一个重定向/重写规则,就像这样:

查看以下链接获取更多信息(以及截图中的复制友好规则):

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

大多数建议的解决方案(尤其是最流行的答案)的问题是,对于不存在的后端资源,您永远不会看到404错误。如果希望继续得到404,请参考此解决方案

I added a root path to all my routes (that's new to this solution) e.g. all my route-paths start with the same front end root... in place of paths /foo/baz, /foo2/baz I now have /root/foo/baz , /root/foo2/baz paths. The choice of the front-end root is such that it does not conflict with any real folder or path at the back-end. Now I can use this root to create simple redirection rules anywhere, I like. All my redirection changes will be impacting only this path and everything else will be as earlier.

这是我在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应用程序后添加了以下代码。它将把我的应用程序带到所需的路线。您可以更换路由器。push部分根据Angular或你正在使用的任何东西。

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

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

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

现在可以使用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);
};

在您的云前行为中,您将编辑它们以在“Viewer Request”上添加对lambda函数的调用

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

这里没有提到的解决方案是使用CloudFront函数在查看器请求时将请求URI重写为index.html:

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

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

事实上,你必须去编辑权限,点击添加更多权限,然后在你的桶中添加正确的列表给每个人。通过此配置,AWS S3现在将能够返回404错误,然后重定向规则将正确地捕获这种情况。

就像这样:

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

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

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

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

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