react-router-dom

时间:2019-03-05 16:50:58

标签: javascript reactjs frontend react-router-v4 react-router-dom

请问我在构建多租户SaaS解决方案时遇到问题。对于每个租户,我希望他们使用一个子域,这样我就可以从URL中获取该子域,并调用返回该租户数据的REST API。

例如

  1. 管理员(完全是另一个应用程序-管理员应用程序)创建了一个租户,其域名为tenant1
  2. 在本地系统上的租户应用程序中,我能够转到tenant1.localhost:3000。我得到的URL,并获得域名。然后,我与域进行通话以获取租户的主题(该主题存储在localStorage中)。

不幸的是,我们在我公司的k8上进行了部署,所以我无法模仿这种行为。因此,devOps团队建议我在上下文中使用子域,从而拥有localhost:3000/tenant1。记住承租人是动态的,所以我尝试了这个:

<BrowserRouter basename={"/:tenant"}>
    <Switch>
        <Route exact path="/login" name="Login" component={Login} />
        <Route exact path="/set-password/:token" name="Set Password" component={SetPassword} />
        <PrivateRoute path="/" name="Default Layout" component={DefaultLayout} /> 
    </Switch>              
</BrowserRouter>

但是上述解决方案使我的URL进入localhost:3000 /:tenant / login

请问我如何在路由器中使用动态基名,以便它可以接受:

localhost:3000/tenant1 localhost:3000/tenant3 localhost:3000/tenant2

它可以允许任何我的应用处理输入的错误域

3 个答案:

答案 0 :(得分:1)

这对我来说可以使用react> 16和react-router-dom v5

export const App = () => {
    return (
        <BrowserRouter>
            <Switch>
                <Route path="/:tenantId?" component={LayoutRoot} />
            </Switch>
        </BrowserRouter>
    );
};

export const LayoutRoot = () => {
    var { tenantId } = useParams();
     //TODO: add some validation here and inform user if tenant is invalid
    return (
        <BrowserRouter basename={tenantId}>
            <Switch>
                <Route path="/login" component={LoginComponent} />
                <Route path="/dashboard" component={DashboardComponent} />
            </Switch>
        </BrowserRouter>
    );
};

答案 1 :(得分:0)

我终于在下面的代码中使用了动态租户

class App extends Component {

    state = {
        domain: ""
    }

    componentWillMount () {
        const { domain } = this.state;

        const parsedData = window.location.pathname.split("/"); 
        let domain = parsedData[1];
        this.setState({ domain: domain })
        this.props.onGetTenant(domain);                
    }

    render () {
        const { domain } = this.state;

        return () {
             <BrowserRouter basename={"/"+domain}>
                <Switch>
                    <Route exact path="/login" name="Login" component={Login} />
                    <Route exact path="/set-password/:token" name="Set Password" component={SetPassword} />
                    <PrivateRoute domain={domain} path="/" name="Default Layout" component={DefaultLayout} /> 
                 </Switch>              
             </BrowserRouter> 
    }

const mapStateToProps = state => {
    const { tenant} = state;
    return { tenant};
};

const mapDispatchToProps = (dispatch) => {
    return {
        onGetTenant: bindActionCreators( tenantActions.get, dispatch)
    }
};

export default connect(mapStateToProps, mapDispatchToProps)(App)

答案 2 :(得分:0)

这是我编写的代码沙盒和实用程序:

https://codesandbox.io/s/react-router-dom-dynamic-basename-xq9tj?file=/index.js

import urlJoin from 'url-join';

// it's important to have an identifier in their app
export const APP_ROOT_URL = '/my-app';

export const getBaseUrlPath = () => {
  const currentPath = document.location.pathname || APP_ROOT_URL;
  const startOfAppBase = currentPath.indexOf(APP_ROOT_URL);

  let base = currentPath;

  if (startOfAppBase !== -1) {
    base = currentPath.substr(0, startOfAppBase);
  }

  base = urlJoin(base, APP_ROOT_URL);

  return base;
};