【问题标题】:Handling Pre-Fetched Dynamic Client Routes in Gatsby / @ReachRouter在 Gatsby / @ReachRouter 中处理预先获取的动态客户端路由
【发布时间】:2019-10-15 23:35:04
【问题描述】:

我有这种情况。

  • 用户在地址栏中输入/company/<company-id>
  • 由于应用与后端完全分离,因此需要预取公司。
  • 普通用户流是/login -> /company/。我很好地处理了这个案例,只需导航到/company/<whatever id is first in the prefetch> 就没有问题。
  • 但是如果你加载 WITH id 呢?我有解决方案,但我觉得我在路由中误解了某些内容。

您可能会认为我的预取有效,并且下面的代码 sn-p 只有在 companyState.success 为真时才会触发。就像我说的,它正在工作。 我手动处理了这个,由

// pretty sure i can handle this with regex better to capture other cases
// but that's beside the point for the scope of this question
const urlId = +location.pathname.replace("/company/", "")
const checkCompany = !!companyState.data.find(d => d.id === urlId)
if(checkCompany){
  company.set(urlId)
}
else{
  navigate("/404")
}

如果company.set(<company:id>) 确实更新了,它会预先获取视图所需的所有其他内容。而且,company 是一个自定义上下文挂钩,因此它在我的应用程序中随处可见。

有没有更好的方法来处理这个问题?手动检查路径名似乎是 hack-y。 您可以假设我的gatsby_node.js 具有正确的定义以允许客户端路由。

这是我的路由定义:(这是我放在 pages 文件夹中的)

const DashboardPage = () => (
  <ProtectedRoute>
    <Router>
      <Company path="/company/*" />
    </Router>
  </ProtectedRoute>
)

终于在components文件夹下,

const Company = ({location}) => (
    <Router>
      <Main path="/:companyId">
        <Summary path="/" />
        .... other dashboard routes
      </Main>
    </Router>
)

【问题讨论】:

    标签: javascript reactjs gatsby reach-router


    【解决方案1】:

    您必须假设客户端代码总是可以被恶意行为者更改。最终,您必须在后端确保用户只能请求他应该看到的资源。

    您的客户端解决方案对我来说似乎很好。除了手动检查 URL 路径然后重定向之外,我没有看到其他方法。

    通过登录,您的用户需要被分配到加密安全的 cookie 或令牌(例如 JSON 网络令牌),以便您始终可以确定他们的身份。每次将公司 ID 路由到时,您的前端都需要将用户身份发送到您的后端。只有在那里你才能免受代码操作的影响。您的后端需要检查用户是否可以查看此页面。

    • 如果用户可以:您的后端发送页面数据
    • 如果用户不能:您的后端发送“未授权”消息并且您的前端重定向

    这样即使有人操纵你的客户端代码并取消重定向,黑客也会盯着一个无用的空白页面。

    总结:

    您在客户端的方法很好。确保您的后端在发送公司数据之前检查用户的身份。

    【讨论】:

    • 是的,后端当然受到保护,毫无疑问。感谢你的回答!我实际上以比我所做的更好的方式解决了它。
    【解决方案2】:

    所以我没有手动处理路由,而是单独使用 ReachRouter 的导航来模拟 history.push() 以避免重新渲染整个页面。 (类似地,只是为了跟踪历史而进行的状态更改)。后端受到身份验证令牌的全面保护,因此无需担心。

    我下面的策略将处理这些情况:

    • 用户输入或应用导航到/company(应用将预取>默认获取第一家公司>导航到/company/{id}
    • 用户输入或应用导航到 /company/{id}(应用将预取 > 导航到 /company/{id} > 由该路由触发的组件将检查 id 的有效性,否则导航到 404)

    我制定的策略是,

    • 创建一个默认加载加载屏幕并预取上述公司的组件。
    • 默认调用pages文件夹中的上述组件,在我的情况下,/company应该是pages &gt; company.jspages &gt; company &gt; index.js
    • 如果预取成功,导航到/company/{id},它是所述组件的子组件,它是一个纯粹的客户端路由。
    • 确保gatsby-node.js 具有必要的createPages 定义以允许客户端路由所有/company/*
    • 手动检查当前位置是否为/company拒绝重定向捕获用户输入/company/{id}时的第二种情况

    如果我显示代码会更好,忽略我自定义的内置钩子。

    useRequest 只是给出了一个 axios 类,true 参数告诉它是一个经过身份验证的必需请求。 useApi 只是提供了一个方便的(async-await)函数,其中包括用于 redux 状态和调用 api 本身的 dispatch。我正在使用 thunk,所以 successerror 是标准的。

    const CompanyDefault = ({location}) => {
    
      const [loading, toggle] = useState(true)
    
      const request = useRequest(true)
      const companyApi = useApi(request, getCompanies)
      const companyState = useSelector(({company}) => company)
      const redirectToCompany = async () => await navigate(clientRoutes.COMPANY(companyState.data[0].id))
    
      const fetchCompanies = async () => {
        await companyApi()
        toggle(false)
      }
    
      useEffect(() => {
        if(companyState.data.length === 0){
          fetchCompanies()
        } 
      }, [])
    
      if(loading){
        return <Loading />
      }
      else if(companyState.error || companyState.data.length === 0){
        return <Error callApi={companyApi} />
      }
      else if(companyState.success && (location.pathname === "/company" || location.pathname === "/company/")){
        redirectToCompany()
      }
    
      return (
        <Router>
          <Company path="company/:companyId/*" />
        </Router>
      )
    }
    
    export default CompanyDefault
    

    因此,公司模块将只是

    const Company = ({companyId}) => (
        // you now have companyId! 
        // do magic here, and check if that company id is valid.
        <Router>
          <Main path="/">
            <Summary path="/" />
            .... other dashboard routes
          </Main>
        </Router>
    )
    

    希望这更清洁。如果有更好的方法请告诉我! :D

    【讨论】:

      猜你喜欢
      • 2019-05-31
      • 2023-03-03
      • 2020-02-29
      • 2020-09-27
      • 1970-01-01
      • 2021-08-10
      • 2020-09-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多