淘先锋技术网

首页 1 2 3 4 5 6 7

aws s3 客户端

作为最近的Bootcamp毕业生,我想将我的新React技能发挥作用,并与AWS结合使用我的旧技能。 我使用React构建了新的投资组合站点,然后我心想:“我可以在S3存储桶中托管它吗?” 第一项任务是部署到S3,这是非常简单的,有很多很好的资源,你可以用一点谷歌搜索发现,像这样的一个 ,步进通过该怎么做。

我正在用新的改进的React网站替换现有网站,因此我已经设置了存储桶并配置了Route 53等。我启动了项目并在浏览器中将其拉出,一切似乎都运行良好。 成功!

但是有一个大问题,如果您在浏览器上单击刷新按钮,则会收到404错误。 怎么会这样 我早些时候在部署到Heroku的一个学校项目中注意到了这一点,但是当时没有时间进行调查,现在我想深入了解它。

通过一些搜索,我找到了一些解决方法的解释和一些方法,但没有找到完整的答案。 关于堆栈溢出的问题, 这里有一个很好的解释,我将尝试自己做一个快速解释。

基本上,由于当您发送刷新命令时,React-router是“客户端”导航,因此浏览器正在进入,它在地址路径的末尾查找索引文件,但没有一个。 因此,在我的投资组合示例中,如果您正在查看“ / About”页面,则在传统的静态网站中,“ / About”文件夹中将有一个索引文件,浏览器将读取该索引文件并将其显示在页面上。

但是在React中,“关于”是React在页面上实例化的组件,但是该路径的末尾没有资源可供浏览器查看。 浏览器实际上总是在站点根目录下查看索引文件,而react-router正在读取地址栏并在组件之间进行切换。

经过更多的谷歌搜索之后,我在Mike Biek的这篇文章中得到了很大一部分解决方案。 此处的重要见解是,您可以使用重定向规则和条件重定向在AWS S3中进行一些“服务器端”路由。 条件重定向使您可以对错误情况做出React,因此,当单击刷新并且页面无法加载时,它将返回404错误。

使用重定向规则,我们可以在前面加上“#!” 在地址前面,浏览器不会在'#'之后读取任何内容,因此将转到您的首页'/'路线页面,但我们仍将在地址栏中提供该地址以供使用。

这是文件,直接复制自Mike Biek的帖子…

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

要找到这些规则的去向,请在您的AWS账户上打开S3服务。 单击您用于托管项目的存储桶,然后单击属性,然后单击显示“静态网站托管。 您会看到一个标有“重定向规则(可选)”的文本框。

将代码复制并粘贴到此处,并确保您使用域的实际名称来编辑“ myhostname.com”。

添加此规则后,刷新时将不再收到404错误。 取而代之的是,您将被路由回到本地路由,无论是从“ /”路由链接到的哪个组件。 这是一个改进,但情况可能会更好。 理想情况下,我们希望路由回到相同的组件,而我的Nav不能反映我正确在哪个页面上,这是一个不同的问题。

回到Mike Biek的帖子 ,他说使用'createBrowserHistory'直接使用路径。 我试图使它起作用,但我无法这样做,经过进一步的谷歌搜索和阅读后发现,createBrowserHistory已被放弃,开发人员应直接使用location道具。 我找不到任何人为此目的使用它的示例,但我有自己的想法。

我必须对定位对象进行一些实验才能弄清楚。 基本上,只要您遵循路线,就可以创建位置对象并将其传递到道具中,实例化该位置对象后,该位置对象将在组件中可用。 在定位对象内部有一个“路径名”键和一个“哈希”键,来自地址栏的路径将是“路径名”值,但是如果地址中有一个“#”,则从“#”开始的所有内容将是“哈希”值。

我的投资组合网站的布局很简单,导航中只有两个项目,一个是“项目”,默认情况下显示,另一个是“关于”页面。

解决方案的第一个迭代是将一个函数放入我的默认组件中,该组件将读取位置对象,并且如果存在哈希变量并且其中包含“#!/ About”,则使用从react-router重定向到About的重定向组件,否则它可能会停留在Projects上。

看起来像这样…

const path = props.history.location

    const checkPath = () => {
        if (path.hash) {
            if (path.hash.includes( '#!/About' )) {
                return < Redirect push to = '/About' > </ Redirect >
            }
        }
    }

现在,单击刷新按钮不会使事情崩溃。 如果您使用的是About,那么您将回到About,如果您使用的是Projects,那么您最终将回到Projects。 过渡将发生得足够快,以至于用户基本上看不见它。 但是我的Nav没有反映出哪个组件正常工作。

因此,在此阶段我需要做的另一件事是提升控制,以显示哪个Nav元素对顶层“ App”组件“处于活动状态”。 我创建了一个名为“ active”的状态,该状态可以保存哪个Nav元素将处于活动状态,然后创建一个函数来设置活动元素,然后将该函数传递给Nav和Project组件。

像这样

class App extends Component  {
  constructor (props) {
    super (props)
    this .state = {
      active : 'Projects'
    }
  }
 setActive = ( str ) => {
    this .setState({ active : str })
  }

这还不能完全正常工作,单击刷新按钮后事情不会再坏了,很好,但是前进和后退按钮仍然会破坏活动的Nav项目,并且它不是一个非常灵活的系统。 重定向仅在两个页面上运行良好,但是,如果我添加了更多页面,则需要一系列的ifs或switch语句,这感觉很笨拙。

我决定再做一次。 首先,我制作了一个helper.js文件,并将我的checkPath函数放在那里。 这样,我可以从每个组件链接到它。 我进行了设置,以便可以在任何页面上使用。

如果该位置存在“哈希”值,则该函数将哈希路径作为变量获取,并去除多余的字符,然后重定向到该项目。 同样,相同的功能将以类似的方式设置活动的导航项目。 看起来像这样…

import React from 'react'
import { Redirect } from 'react-router-dom'

export function checkPath ( props )  {
   const path = props.state.history.location
   if (path.hash) {
       let active = path.hash.replace( /\/|!|#/g , '' )
       active = '/' + active
       return < Redirect push to = {active} > </ Redirect >
   }
   if (path.pathname) {
       let active = path.pathname.replace( /\//g , '' )
       props.setActive(active)
   }

}

接下来,我将setActive函数传递给其Route声明中的每个组件,并在该组件内部导入setPath helper函数,然后在该组件的return语句内调用它。 您必须确保将道具传递到checkPath函数中,以便它可以使用setActive函数。

另外,我的setActive函数还需要做更多的工作,以确保正确的Nav项目在'/'路径上设置为活动状态,并防止setState调用启动无限循环。 您将在下面的代码中看到。

现在,我没有要显示服务器端的“ 404”错误页面,因此需要解决的另一个问题是,我需要设置一个默认路由或全部路由,以在错误链接或手动键入的路径上显示一条消息,而不显示错误消息。比赛。 这只需要添加一个最终的Route即可显示一个组件,如果其他Routes都不匹配,则我将其称为“ NoMatch”。

关于我的代码的另一个说明,我通过“状态”沿路线发送道具,您可以随意调用它们,但如果不隐式传递它们,则它们将无法在组件中访问。 在另一个项目上,我感到非常沮丧,这很艰难。

将所有这些放在一起看起来像…

在App.js中...

class App extends Component  {
  constructor (props) {
    super (props)
    this .state = {
      active : 'Projects'
    }
  }

  setActive = ( str ) => {
    if (!str) {
      str = 'Projects'
    }
    if ( this .state.active !== str) {
      this .setState({ active : str })
    }
  }

  render() {
    return (
      < div className = "App flex-container-column" >
         <div className="container flex-container-column">
          <Header></Header>
          <Nav active={this.state.active}></Nav>
          <Switch>
            <Route path="/" exact render={props => <Projects setActive={this.setActive} state={props} />} />
            <Route path="/About/" render={props => <Home setActive={this.setActive} state={props} />} />
            <Route path="/Projects/" render={props => <Projects setActive={this.setActive} state={props} />} />
            <Route path="/" render={props => <NoMatch setActive={this.setActive} state={props} />} />
          </Switch>
        </div>
        <Footer></Footer>
      </div>
    );
  }
}

在您的组件中,它看起来像这样...

import { checkPath } from '../helpers'

function NoMatch ( props )  {
    return (

        < div >
             <div className="flex-container-column centered">
                {checkPath(props)}
                <div className='short'>
                    <p>Hmm, There doesn't seem to be anything here... Go back <Link to="/">Home?</Link></p>
                </div>
            </div> 

        </ div >
    )
}

该解决方案效果很好,但并不完美。 如果用户单击刷新,则后退按钮将无法越过该点,因为它将无休止地转到哈希路由,然后重定向到非哈希路由。 另外,除非您设置了某种服务器端路由,否则SEO在第一页之后将找不到任何内容。

但是,对于很少的单页应用程序,项目组合和其他简单项目,这是一个很好的解决方案。

James C Rodgers是AWS认证的云实践者,并且是General Assemb.ly全栈软件工程沉浸式远程程序的最新毕业生

照片由 尤利娅Kosolapova Unsplash ,由JCR编辑

翻译自: https://hackernoon.com/handling-client-side-routing-when-hosting-your-reactjs-project-on-aws-s3-da6j3veq

aws s3 客户端