Javascript react路由器dom中带BrowserRouter的动态basename

Javascript react路由器dom中带BrowserRouter的动态basename,javascript,reactjs,frontend,react-router-v4,react-router-dom,Javascript,Reactjs,Frontend,React Router V4,React Router Dom,我在构建多租户SaaS解决方案时遇到了一个问题。对于每个租户,我希望他们使用子域,这样我就可以从url获取子域,调用RESTAPI返回关于该租户的数据 比如说, 管理员(另一个应用程序完全是管理员应用程序)创建一个域名为:tenat1的租户 在本地系统上的租户应用程序中,我可以转到tenant1.localhost:3000。我得到了网址和域名。然后,我对域进行调用,以获取租户的主题(该主题存储在localStorage中) 不幸的是,我们公司部署在k8上,所以我无法模仿这种行为。因此,devO

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

比如说,

  • 管理员(另一个应用程序完全是管理员应用程序)创建一个域名为:
    tenat1
    的租户
  • 在本地系统上的租户应用程序中,我可以转到
    tenant1.localhost:3000
    。我得到了网址和域名。然后,我对域进行调用,以获取租户的主题(该主题存储在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

    请说明如何在路由器中使用dynamic basename,以便它可以接受:

    localhost:3000/tenant1
    localhost:3000/租户3
    localhost:3000/租户2


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

    我最终使用动态租户,代码如下

    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)
    
    类应用程序扩展组件{
    状态={
    域名:“
    }
    组件将安装(){
    const{domain}=this.state;
    const parsedData=window.location.pathname.split(“/”);
    let domain=parsedData[1];
    this.setState({domain:domain})
    this.props.onGetTenant(域);
    }
    渲染(){
    const{domain}=this.state;
    返回(){
    }
    常量mapStateToProps=状态=>{
    const{tenant}=状态;
    返回{租户};
    };
    const mapDispatchToProps=(调度)=>{
    返回{
    onGetTenant:bindActionCreators(tenantActions.get,dispatch)
    }
    };
    导出默认连接(mapStateToProps、mapDispatchToProps)(应用程序)
    
    这对我使用react>16和react路由器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>
        );
    };
    
    export const App=()=>{
    返回(
    );
    };
    导出常量LayoutRoot=()=>{
    var{tenantId}=useParams();
    //TODO:在此处添加一些验证,并在租户无效时通知用户
    返回(
    );
    };
    
    下面是一个codesandbox和我编写的实用程序:


    在这种情况下,package.json中的“basename”应该是什么?我尝试过使用您的解决方案,但当我登录到我的应用程序时,basename没有改变。您可以共享您的PrivateRoute组件吗?package.json中的主页应该是什么?
    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;
    };