我使用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执行所有操作非常有吸引力。


当前回答

让Angular 2+应用程序通过Amazon S3和直接url工作的最简单的解决方案是在S3桶配置中指定Index .html作为Index和Error文档。

其他回答

其他人提到的基于S3/Redirect的方法有一些问题。

多重重定向发生在应用程序的路径被解析时。例如:www.myapp.com/path/for/test被重定向为www.myapp.com/#/path/for/test 由于您的SPA框架的操作,当“#”出现和消失时,url栏中有一个闪烁。 seo会受到影响,因为——‘嘿!这谷歌迫使他的手重定向 Safari对你的应用程序的支持值得一试。

解决方案是:

Make sure you have the index route configured for your website. Mostly it is index.html Remove routing rules from S3 configurations Put a Cloudfront in front of your S3 bucket. Configure error page rules for your Cloudfront instance. In the error rules specify: Http error code: 404 (and 403 or other errors as per need) Error Caching Minimum TTL (seconds) : 0 Customize response: Yes Response Page Path : /index.html HTTP Response Code: 200 For SEO needs + making sure your index.html does not cache, do the following: Configure an EC2 instance and setup an nginx server. Assign a public ip to your EC2 instance. Create an ELB that has the EC2 instance you created as an instance You should be able to assign the ELB to your DNS. Now, configure your nginx server to do the following things: Proxy_pass all requests to your CDN (for index.html only, serve other assets directly from your cloudfront) and for search bots, redirect traffic as stipulated by services like Prerender.io

我可以提供更多关于nginx设置的细节,请留下一张便条。经历了惨痛的教训。

一旦云前端分发更新。使您的云前缓存失效一次,使其处于原始模式。 在浏览器中点击url,一切都应该是好的。

我做到这一点的方法如下:

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

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

这将导致404错误的所有路径重定向到根域,并显示路径的散列版本。所以http://yourdomainname.com/posts将重定向到http://yourdomainname.com/#!如果/posts上没有文件。

然而,要使用HTML5的pushState,我们需要接受这个请求,并根据散列路径手动建立正确的pushState。所以把这个添加到index.html文件的顶部:

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

这将获取散列并将其转换为HTML5 pushState。从这一点开始,你可以使用pushStates在你的应用程序中拥有非哈希键路径。

我今天遇到了同样的问题,但是@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('!');

大多数建议的解决方案(尤其是最流行的答案)的问题是,对于不存在的后端资源,您永远不会看到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的另一个答案类似,您可以使用Cloudfront函数(截至2021年8月,它是免费层的一部分)。

我的URL结构是这样的:

React SPA托管在S3上 example.com/blog -博客托管在EC2上

由于我将博客托管在与SPA相同的域上,所以我不能使用Cloudfront 403/404错误页面使用默认错误页面的建议答案。

我的Cloudfront设置是:

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

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

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;
}