如何处理对客户端反应应用程序的外部重定向?

Posted

技术标签:

【中文标题】如何处理对客户端反应应用程序的外部重定向?【英文标题】:How do I handle external redirects to a client side react app? 【发布时间】:2020-03-01 06:12:45 【问题描述】:

我正在构建一个使用 True Layer 开放式银行 API 的网络应用程序。该应用程序有一个使用 React 路由器的 React 前端和一个 Express 和 Nodejs 后端。目前我正在使用 react build 脚本来提供静态文件:

const app = express();

app.use(cors());
app.use(express.json());

app.use(express.static('../client/build'));
app.get('*', (req, res) => 
    res.sendFile('index.html', root: path.join(__dirname, '../client/build/'));
);

const PORT = process.env.PORT || 3001;
app.listen(PORT, () => 
    console.log("Server listening on port: ", PORT);
);

// The API routes are imported below

这个解决方案效果很好,但是当用户被重定向到 True Layer 的身份验证页面时,会生成 OAuth 代码并作为 url 查询传递回客户端上的路由。问题是,当 True Layer 将用户重定向回我的应用程序时,url 由服务器而不是 react 路由器/浏览器解释,因此它返回cannot GET /myAccounts。我已经研究过使用 Next.js 之类的库为 React 客户端使用服务器端渲染,但我想知道是否有一种方法可以做到这一点,而无需大幅重构我的代码。

我的 React 路由器设置:

class App extends Component 
    render() 
        return (
            <Router>
                <Route name="Landing" path="/" exact component=Login />
                <Route name="Login" path="/login" exact component=Login />
                <Route name="MyAccounts" path="/myAccounts" exact component=Home />
            </Router>
        );
    

/myAccounts 路由渲染Home 组件/页面,其中提取了code 参数:qs.parse(props.location.search)['?code'],并发送到我的服务器以完成 OAuth 过程。

任何帮助将不胜感激。

【问题讨论】:

剩下的路线是什么?你有一个app.get('*', ...),它应该会捕获所有的 GET 请求,所以不会加起来。 @Jacob 其余路由只是查询外部 API 或处理数据的 GET 和 POST 路由的分类。问题是,当 True Layer 的身份验证页面将用户重定向回我在 /myAccounts?code=478hds... 的应用程序时,服务器的行为就好像它是对其中一个路由的请求,但该请求是针对 React DOM 路由器的 /myAccounts 路由的code 参数被提取:qs.parse(props.location.search)['?code'] 并发送回我的服务器以完成 OAuth 过程。抱歉,如果我最初的问题不清楚,我现在将对其进行编辑。 您无法避免来自单独站点的重定向访问您的服务器,如果这就是您所追求的。您真正能做的就是确保您的服务器为这些请求提供页面。如果此“True Layer”登录页面是一个单独的站点,您的原始文档将被卸载。 @Jacob 是的,这是有道理的,我认为会是这种情况,但希望我可以使用某种技巧来保持页面加载/不需要 s-s-r。不过感谢您的帮助。 【参考方案1】:

问题是当 True Layer 将用户重定向回我的应用程序时,url 由服务器解释,而不是 react 路由器/浏览器,因此它返回不能 GET /myAccounts

会发生什么: 路径 /myAccounts 是 React SPA 的内部路径,它显示由 MyAccounts 组件呈现的内部 SPA 页面。网络服务器不知道此页面并返回“无法 GET /myAccounts”。此网络服务器行为不正确不是因为网络服务器不支持 True Layer/OAuth,而是因为网络服务器不正确支持 SPA。

应该发生什么: Web 服务器应该通过实现回退行为来支持 SPA,这意味着服务器将对未知页面的请求重定向到 SPA 登录页面。例如,此行为在 webpack-dev-server 中使用 historyApiFallback 启用,该 historyApiFallback 专门用于支持 SPA。

任何 SPA 都需要后备行为,因为用户可以在导航栏中看到任何内部页面的路径,并且可以手动重新键入并按 Enter 或刷新浏览器。在这两种情况下,网络服务器都会收到对其不知道的内部 SPA 页面的请求,并且以 404 错误响应对用户来说并不好。

在 Express 中实现回退后,您可以将一条数据添加到重定向到着陆页的请求中。这样您的Landing 组件就会看到这个可选部分并在内部(网络服务器不知道)重定向到MyAccounts 组件。

【讨论】:

谢谢!我看到了这样的解决方案,但它需要使用 webpack 设置来实现,我的客户端 SPA 没有配置 atm。我找到了This npm module,我认为它会这样做,但它似乎只是一条为index.html 提供服务的所有路由,它让我进入一个失败的重定向循环,返回到登录页面。我似乎找不到任何在 Express 中实现后备的方法。我并不完全反对实施 webpack,但如果有一种使用 Express 的方法,那将是首选。 我写了一个样板文件Crisp React,它在 webpack-dev-server 和Express 中实现了回退。对于后者,有一个test case 来测试后备重定向。尽管它是用 TypeScript 编写的,但我希望你会发现这个项目很有用。有一个关于它的article。 这看起来很棒谢谢你我试着只挑选 Express 后备并写了this。这会导致无限重定向循环,目前我只是检查 url 是 /myAccounts 还是 /login,然后我只是在它的入口点为完整构建的客户端提供服务,在那里它检查 JWT,然后如果找到了尝试重定向到/myAccounts 并循环回/ - 这也导致我的正常REST API 路由返回构建客户端的html。有点卡在这里:/【参考方案2】:

附言 为了迎合登录需要修改逻辑。 在这种情况下,首选(并且逻辑上更简单/清晰)的选项是拥有 2 个 SPA:打开用于登录,另一个用于应用程序的其余部分。但我知道这意味着对现有应用程序进行更多更改,这就是为什么您更喜欢仅更改 Express 端。这可以做到,但逻辑变得更加复杂。

客户端 在您可以拥有的唯一 SPA 的唯一入口点中:

<Switch>
  <Route exact path="/" component=Home />
  <Route path="/login" component=Login />
  <Route path="/myaccount" component=either Login or maybe MyAccount />
  <Route component=Home />
</Switch>

Home 组件应验证客户端是否已登录(例如通过在成功登录后检查 Express 或外部云服务器设置的 cookie),如果未在内部(history.push)重定向到/login。以同样的方式Login 组件应该检查​​客户端是否已经过身份验证,如果是,则在内部重定向到'/',例如到Home 组件。

表达侧逻辑

/ - 服务index.html(React build 生成的唯一 .html 文件,因为你有一个 SPA)最终进入路由器,由于第一个 @987654331,路由器将渲染 Home 组件@

/index – 服务index.html。由于第 4 个&lt;Route&gt;,路由器将渲染Home 组件。

/login – 服务index.html。这是一个后备(例如已经登录的用户可以手动输入此路径)。由于第二个&lt;Route&gt;,路由器将渲染Login组件

/myaccount – 服务index.html。由于第三个&lt;Route&gt;,路由器将渲染Login 组件。该组件应该能够获得?code=123bac...

看起来没有恶意的未知页面。它可能是用户重新输入的 SPA 的某些内部页面的内部路径。回退到 '/' 以显示 Home 组件。

【讨论】:

以上是关于如何处理对客户端反应应用程序的外部重定向?的主要内容,如果未能解决你的问题,请参考以下文章

如何处理“太多 HTTP 重定向”错误

如何处理 C++ 重定向进程的输出

Service Worker:如何处理 302 重定向响应

WPF 如何处理对空对象属性的绑定?

Falcor 模型如何处理对字符串的引用?

如何处理对 UITableView 的非单元格区域的点击