路由、react-admin 的问题

问题描述 投票:0回答:1

当您登录管理员帐户时,会重定向到react-admin页面,然后重定向到/users(http://localhost:3000/admin#/users)。此页面上没有任何内容。我不明白什么是冲突以及为什么会发生这种情况,没有错误。请帮帮我。 (ip改为...)

后端部分

main.js:

const express = require('express');
    const mongoose = require('mongoose');
    const swaggerUi = require('swagger-ui-express');
    const swaggerDocs = require('./Other/SwaggerDoc/swaggerDoc');
    const bookRoutes = require('./Books/booksRoutes');
    const userRoutes = require('./User/userRoutes');
    const authRoutes = require('./User/authRoutes')
    const passport = require('./User/passportConfig');
    const cors = require('cors');
    const corsConfig = require('./Other/corsConfig');
    const session = require('express-session');
    const app = express();
     
    app.use(express.json());
    app.use(session({
      secret: '',
      resave: false,
      saveUninitialized: false
    }));
    app.use(passport.initialize());
    app.use(passport.session());
    app.use(cors(corsConfig));
     
     
    async function connectToDatabase() {
      const uris = [
        'mongodb://.../bookapi',
        'mongodb://.../bookapi'
      ];
      
      for (let uri of uris) {
        try {
          await mongoose.connect(uri, {useNewUrlParser: true, useUnifiedTopology: true});
          console.log(`Connected to ${uri}`);
          break;
        } catch (err) {
          console.log(`Failed to connect to ${uri}`);
        }
      }
    }
     
    connectToDatabase();
     
    app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocs));
    app.use('/api/books', bookRoutes);
    app.use('/api/users', userRoutes);
    app.use('/auth', authRoutes);
     
    app.listen(3001, () => console.log('Listening on port 3001...'));

用户.js:

const mongoose = require('mongoose');
    const bcrypt = require('bcrypt');
     
    let userId = 0;
     
    const userSchema = new mongoose.Schema({
      id: Number,
      email: {
        type: String,
        required: true,
        maxlength: 100,
        validate: {
          validator: function(v) {
            return /^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$/.test(v);
          },
          message: props => `${props.value} invalid email`
        }
      },
      password: {
        type: String,
        required: true,
        validate: {
          validator: function(v) {
            return v.length >= 8 && v.length <= 32;
          },
          message: 'password length should be 8 - 32 symbols'
        }
      },
      role: {
        type: String,
        enum: ['user', 'admin'],
        default: 'user'
      }
    });
     
     
    userSchema.pre('save', async function(next) {
      let user = this;
      if (user.isNew) {
        const maxUser = await User.find().sort('-id').limit(1);
        const maxId = maxUser.length > 0 ? maxUser[0].id : 0;
        user.id = maxId + 1;
      }
      if (user.isModified('password')) {
        user.password = await bcrypt.hash(user.password, 8);
      }
      next();
    });
     
    const User = mongoose.model('User', userSchema);
     
    module.exports = User;

userRoutes.js:

const express = require('express');
    const User = require('./user');
    const router = express.Router();
     
    router.post('/', async (req, res) => {
        try {
          const user = new User(req.body);
          await user.save();
          const userResponse = await User.findOne({id: user.id}).select('-_id -__v');
          res.status(201).send(userResponse);
        } catch (error) {
          res.status(400).send(error);
        }
      })  
     
    router.get('/:id', async (req, res) => {
      try {
        const user = await User.findOne({id: req.params.id}).select('-_id -__v');
        if (!user) {
          return res.status(404).send();
        }
        res.send(user);
      } catch (error) {
        res.status(500).send(error);
      }
    });
     
    router.put('/', async (req, res) => {
      try {
        const user = await User.findOneAndUpdate({id: req.body.id}, req.body, { new: true, runValidators: true }).select('-_id -__v');
        if (!user) {
          return res.status(404).send();
        }
        res.send(user);
      } catch (error) {
        res.status(400).send(error);
      }
    });
     
    router.delete('/:id', async (req, res) => {
      try {
        const user = await User.findOneAndDelete({id: req.params.id}).select('-_id -__v');
        if (!user) {
          return res.status(404).send();
        }
        res.send(user);
      } catch (error) {
        res.status(500).send(error);
      }
    });
     
    router.get('/users', async (req, res) => {
      const users = await User.find().select('-_id -__v');
      res.send(users);
    });
     
    module.exports = router;

passportConfig.js:

const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const User = require('./user');
const bcrypt = require('bcrypt');
 
passport.use(new LocalStrategy({ usernameField: 'email' },
  async (email, password, done) => {
    try {
      const user = await User.findOne({ email });
      if (!user) {
        return done(null, false, { message: 'Incorrect email.' });
      }
      if (!await bcrypt.compare(password, user.password)) {
        return done(null, false, { message: 'Incorrect password.' });
      }
      return done(null, user);
    } catch (error) {
      return done(error);
    }
  }
));
 
passport.serializeUser((user, done) => {
    done(null, user.id);
  });
  
  passport.deserializeUser((id, done) => {
    User.findById(id, (err, user) => {
      done(err, user);
    });
  });  
 
module.exports = passport;
```

authRoutes.js:

```
const express = require('express');
const passport = require('./passportConfig');
const User = require('./user');
const router = express.Router();
 
router.post('/login', passport.authenticate('local'), async (req, res) => {
    const user = await User.findOne({ email: req.user.email }).select('-_id -__v');
    res.send(user);
  });
 
router.get('/logout', (req, res) => {
  req.logout();
  res.send('Logged out');
});
 
module.exports = router;

corsConfig.js:

const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const User = require('./user');
const bcrypt = require('bcrypt');
 
passport.use(new LocalStrategy({ usernameField: 'email' },
  async (email, password, done) => {
    try {
      const user = await User.findOne({ email });
      if (!user) {
        return done(null, false, { message: 'Incorrect email.' });
      }
      if (!await bcrypt.compare(password, user.password)) {
        return done(null, false, { message: 'Incorrect password.' });
      }
      return done(null, user);
    } catch (error) {
      return done(error);
    }
  }
));
 
passport.serializeUser((user, done) => {
    done(null, user.id);
  });
  
  passport.deserializeUser((id, done) => {
    User.findById(id, (err, user) => {
      done(err, user);
    });
  });  
 
module.exports = passport;
```

authRoutes.js:

```
const express = require('express');
const passport = require('./passportConfig');
const User = require('./user');
const router = express.Router();
 
router.post('/login', passport.authenticate('local'), async (req, res) => {
    const user = await User.findOne({ email: req.user.email }).select('-_id -__v');
    res.send(user);
  });
 
router.get('/logout', (req, res) => {
  req.logout();
  res.send('Logged out');
});
 
module.exports = router;

前端部分

App.js:

    const corsConfig = {
      origin: 'http://localhost:3000',
      methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
      credentials: true,
      allowedHeaders: ['Content-Type', 'Authorization'],
      exposedHeaders: ['X-Total-Count']
    };
     
    module.exports = corsConfig;

AppRouter.jsx:

import AppRouter from './components/AppRouter';
    import './index.css';
    import {HashRouter} from "react-router-dom";
    function App() {
      return (
        <HashRouter>
          <div className="App">
            <AppRouter/>
          </div>
        </HashRouter>
      );
    }
     
    export default App;

路由器/index.js:

import React, { useEffect } from 'react'
    import { Routes, Route, useNavigate, Outlet} from "react-router-dom";
    import { Links } from '../router'
    function AppRouter() {
      const navigate = useNavigate();
      useEffect(() => {
        navigate('/login')
      }, []);
      return (
        <Routes>
          <Route path="/*" element={<Outlet />} />
          {Links.map(route => {
            return (
              <Route
                element={React.createElement(route.component)}
                path={route.path}
                exact={route.exact}
              />
            );
          })}
        </Routes>
      )
    }
    export default AppRouter

登录.jsx:

import AdminInt from "../pages/Admin/AdminInt";
    import Login from "../pages/Login/Login";
    export const Links = [
        {path: '/login', component: Login, exact: true},
        {path: '/admin/*', component: AdminInt , exact: true}
    ]

AdminInt.jsx:

import React, { useState } from 'react';
    import { useLogin, useNotify } from 'react-admin';
    import { useNavigate } from 'react-router-dom';
     
    const Login = () => {
      const [email, setEmail] = useState('');
      const [password, setPassword] = useState('');
      const login = useLogin();
      const notify = useNotify();
      const navigate = useNavigate();
     
      const handleSubmit = async (event) => {
        event.preventDefault();
        login({ email, password })
          .then(() => {
            notify('Successfully logged in', 'info');
            navigate('/admin');
          })
          .catch((error) => {
            notify('Invalid email or password', 'warning');
          });
      };  
     
      return (
        <form onSubmit={handleSubmit}>
          <label>
            Email:
            <input type="email" value={email} onChange={e => setEmail(e.target.value)} required />
          </label>
          <label>
            Password:
            <input type="password" value={password} onChange={e => setPassword(e.target.value)} required />
          </label>
          <button type="submit">Log in</button>
        </form>
      );
    };
     
    export default Login;

工具.jsx:

import React from "react";
    import { Admin, Resource } from 'react-admin';
    import dataProvider from "../../components/Admin/dataProvider";
    import { UserList, UserEdit, UserCreate } from '../../components/Admin/Tools';
    const AdminInt = () => (
        <Admin dataProvider={dataProvider}>
            <Resource name="users" list={UserList} edit={UserEdit} create={UserCreate} />
        </Admin>
    );
     
    export default AdminInt;

dataProvider.js:

import React from "react";
    import { List, Datagrid, TextField, EmailField, Edit, SimpleForm, TextInput, SelectInput, Create  } from 'react-admin';
     
    export const UserList = props => (
        <List {...props}>
            <Datagrid rowClick="edit">
                <TextField source="id" />
                <TextField source="role" />
                <EmailField source="email" />
            </Datagrid>
        </List>
    );
     
    export const UserEdit = props => (
        <Edit {...props}>
            <SimpleForm>
                <TextInput disabled source="id" />
                <TextInput source="email" />
                <TextInput source="password" type="password" />
                <SelectInput source="role" choices={[
                    { id: 'user', name: 'user' },
                    { id: 'admin', name: 'admin' }
                ]} />
            </SimpleForm>
        </Edit>
    );
     
    export const UserCreate = props => (
        <Create {...props}>
            <SimpleForm>
                <TextInput source="email" />
                <TextInput source="password" type="password" />
                <SelectInput source="role" choices={[
                    { id: 'user', name: 'user' },
                    { id: 'admin', name: 'admin' }
                ]} />
            </SimpleForm>
        </Create>
    );

javascript reactjs node.js mongodb react-router
1个回答
0
投票

在您的 userRoutes.js 文件中,您有以下设置:

import { fetchUtils } from 'react-admin';
    import { stringify } from 'query-string';
     
    const apiUrl = 'http://.../api';
    const httpClient = (url, options = {}) => {
      if (!options.headers) {
        options.headers = new Headers({ Accept: 'application/json' });
      }
      const token = localStorage.getItem('token');
      options.headers.set('Authorization', `Bearer ${token}`);
      return fetchUtils.fetchJson(url, options);
    }
     
     
    export default {
      getList: (resource, params) => {
          const { page, perPage } = params.pagination;
          const { field, order } = params.sort;
          const query = {
            sort: JSON.stringify([field, order]),
            range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
            filter: JSON.stringify(params.filter),
          };
          const url = `${apiUrl}/${resource}?${stringify(query)}`;
      
          return httpClient(url).then(({ headers, json }) => {
            headers.set('X-Total-Count', json.length);
            return {
              data: json,
              total: parseInt(headers.get('x-total-count').split('/').pop(), 10),
            };
          });
        },
     
      getOne: (resource, params) =>
        httpClient(`${apiUrl}/${resource}/${params.id}`).then(({ json }) => ({
          data: json,
        })),
     
      getMany: (resource, params) => {
        const query = {
          filter: JSON.stringify({ id: params.ids }),
        };
        const url = `${apiUrl}/${resource}?${stringify(query)}`;
        return httpClient(url).then(({ json }) => ({ data: json }));
      },
     
      getManyReference: (resource, params) => {
        const { page, perPage } = params.pagination;
        const { field, order } = params.sort;
        const query = {
          sort: JSON.stringify([field, order]),
          range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
          filter: JSON.stringify({ ...params.filter, [params.target]: params.id }),
        };
        const url = `${apiUrl}/${resource}?${stringify(query)}`;
     
        return httpClient(url).then(({ headers, json }) => ({
          data: json,
          total: parseInt(headers.get('x-total-count').split('/').pop(), 10),
        }));
      },
     
      update: (resource, params) =>
        httpClient(`${apiUrl}/${resource}/${params.id}`, {
          method: 'PUT',
          body: JSON.stringify(params.data),
        }).then(({ json }) => ({ data: json })),
     
      updateMany: (resource, params) => {
        const query = {
          filter: JSON.stringify({ id: params.ids }),
        };
        return httpClient(`${apiUrl}/${resource}?${stringify(query)}`, {
          method: 'PUT',
          body: JSON.stringify(params.data),
        }).then(({ json }) => ({ data: json }));
      },
     
      create: (resource, params) =>
        httpClient(`${apiUrl}/${resource}`, {
          method: 'POST',
          body: JSON.stringify(params.data),
        }).then(({ json }) => ({
          data: { ...params.data, id: json.id },
        })),
     
      delete: (resource, params) =>
        httpClient(`${apiUrl}/${resource}/${params.id}`, {
          method: 'DELETE',
        }).then(({ json }) => ({ data: json })),
     
      deleteMany: (resource, params) => {
        const query = {
          filter: JSON.stringify({ id: params.ids }),
        };
        return httpClient(`${apiUrl}/${resource}?${stringify(query)}`, {
          method: 'DELETE',
        }).then(({ json }) => ({ data: json }));
      },
    };

在你的 main.js 文件中你有这样的设置:

router.get('/users', async (req, res) => {
      const users = await User.find().select('-_id -__v');
      res.send(users);
    });
在这种安排中,终点实际上是

app.use('/api/users', userRoutes);

。
在您的 
/api/users/users
 文件中,您正在导入 
AdminInt.jsx
,它可能会在您进行设置的 
<UserList/>
 中调用某些 api 

dataProvider.js
因此您可能会点击 

const url = `${apiUrl}/${resource}?${stringify(query)}`;

 而不是 
/api/users/users
,这可能会导致问题。

还要检查 chrome 中的网络选项卡,看看您的 api 请求是否成功。

© www.soinside.com 2019 - 2024. All rights reserved.