我使用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/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,一切都应该是好的。

其他回答

现在可以使用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/

大多数建议的解决方案(尤其是最流行的答案)的问题是,对于不存在的后端资源,您永远不会看到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级别使用重定向,在您可能喜欢的任何其他重定向中,为所有路由提供一个单一的基础也会很方便。它帮助后端识别这不是一个真正的后端资源的请求,前端应用程序将能够处理它。

对于这个问题,我有4种解决方案。前三个问题已经在答案中提到了,最后一个是我的贡献。

Set the error document to index.html. Problem: the response body will be correct, but the status code will be 404, which hurts SEO. Set the redirection rules. Problem: URL polluted with #! and page flashes when loaded. Configure CloudFront. Problem: all pages will return 404 from origin, so you need to chose if you won't cache anything (TTL 0 as suggested) or if you will cache and have issues when updating the site. Prerender all pages. Problem: additional work to prerender pages, specially when the pages changes frequently. For example, a news website.

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

关于403禁忌错误,我不让它们发生。在我的应用程序中,我认为主机桶中的所有文件都是公共的,我用具有读权限的everyone选项设置了这一点。如果您的站点有私有页面,让用户看到HTML布局应该不是问题。您需要保护的是数据,这是在后端完成的。

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

在CloudFront的帮助下,不需要url黑客就可以很容易地解决这个问题。

创建S3桶,例如:react 使用以下设置创建CloudFront发行版: 默认根对象:index.html 来源域名:S3桶域名,例如:react.s3.amazonaws.com 转到错误页面选项卡,单击创建自定义错误响应: HTTP错误码:403:禁止(404:未找到,在S3静态网站的情况下) 自定义错误响应:是 响应页面路径:/index.html HTTP响应码:200:OK 点击创建

转到你的桶的静态网站托管设置 设置“Error document”为index.html。