如何处理对客户端反应应用程序的外部重定向?
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 个<Route>
,路由器将渲染Home
组件。
/login
– 服务index.html
。这是一个后备(例如已经登录的用户可以手动输入此路径)。由于第二个<Route>
,路由器将渲染Login
组件
/myaccount
– 服务index.html
。由于第三个<Route>
,路由器将渲染Login
组件。该组件应该能够获得?code=123bac...
看起来没有恶意的未知页面。它可能是用户重新输入的 SPA 的某些内部页面的内部路径。回退到 '/' 以显示 Home
组件。
【讨论】:
以上是关于如何处理对客户端反应应用程序的外部重定向?的主要内容,如果未能解决你的问题,请参考以下文章