加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

reactjs – 服务器呈现泄露用户的Redux存储数据的React ExpressJ

发布时间:2020-12-15 20:11:55 所属栏目:百科 来源:网络整理
导读:我有一个ExpressJS服务器,有时在初始渲染时呈现错误的用户数据.请参阅下面的(稍微简化)版本. 问题是index.ejs文件经常在reduxState中呈现错误的用户数据… 我的困惑是因为我希望从’routes.js’导入{store}的调用以每个用户的请求覆盖商店{}.问题似乎是商店
我有一个ExpressJS服务器,有时在初始渲染时呈现错误的用户数据.请参阅下面的(稍微简化)版本.

问题是index.ejs文件经常在reduxState中呈现错误的用户数据…

我的困惑是因为我希望从’routes.js’导入{store}的调用以每个用户的请求覆盖商店{}.问题似乎是商店正在成为网站上每个用户组合在一起的组合商店.

如何确保每个用户只能看到他们在网站上的数据?

routes.js

// src/routes.js
import React from 'react';
import { createStore,applyMiddleware,compose } from "redux";
import routerConfig from "base/routes/routes";
import thunk from "redux-thunk";
import { rootReducer } from "base/reducers";

let initialState = {};

const store = createStore(
  rootReducer,initialState,compose(applyMiddleware(thunk))
);

const routes = routerConfig(store);

export {store};
export default routes;

server.js

import { store } from 'routes';

let getReduxPromise = (renderProps,request) => {
  let store = require('./routes/index.jsx').store
  let { query,params } = renderProps

  let comp = renderProps.components[renderProps.components.length - 1];

  let at = null;

  if (request && request.cookies && request.cookies.accessToken) {
    at = request.cookies.accessToken
  }

  if (comp.fetchData) {
    return comp.fetchData({ query,params,store,at }).then(response => {
      if (request) {
        if (request.cookies && request.cookies.accessToken && request.cookies.userInfo) {
          store.dispatch(
            actions.auth(request.cookies.userInfo),request.cookies.accessToken
          )
        } else {
          store.dispatch(actions.logout())
        }

      }
      return Promise.resolve({response,state: store.getState()})
    });
  } else {
    return Promise.resolve();
  }
}

app.get('*',(request,response) => {
  let htmlFilePath = path.resolve('build/index.html' );
  // let htmlFilePath = path.join(__dirname,'/build','index.html');
  let error = () => response.status(404).send('404 - Page not found');
  fs.readFile(htmlFilePath,'utf8',(err,htmlData) => {
    if (err) {
      console.log('error 1')
      error();
    } else {
      match({routes,location: request.url},redirect,renderProps) => {
        if (err) {
          console.log('error 2')
          error();
        } else if (redirect) {
          return response.redirect(302,redirect.pathname + redirect.search)
        } else if (renderProps) {
          let parseUrl = request.url.split('/');

          if (request.url.startsWith('/')) {
            parseUrl = request.url.replace('/','').split('/');
          }

          // User has a cookie,use this to help figure out where to send them.
          if (request.cookies.userInfo) {
            const userInfo = request.cookies.userInfo

            if (parseUrl[0] && parseUrl[0] === 'profile' && userInfo) {
              // Redirect the user to their proper profile.
              if (renderProps.params['id'].toString() !== userInfo.id.toString()) {
                parseUrl[1] = userInfo.id.toString();
                const url = '/' + parseUrl.join('/');
                return response.redirect(url);
              }
            }
          }

          getReduxPromise(renderProps,request).then((initialData) => {
            let generatedContent = initialData.response ? render(request,renderProps,initialData.response) : render(request,{});

            const title = initialData.response.SEO.title || '';
            const description = initialData.response.SEO.description || '';

            var draft = [];

            const currentState =  initialData.state;

            if (currentState) {
              const reduxState = JSON.stringify(currentState,function(key,value) {
                if (typeof value === 'object' && value !== null) {
                  if (draft.indexOf(value) !== -1) {
                    // Circular reference found,discard key
                    return;
                  }
                  // Store value in our collection
                  draft.push(value);
                }
                return value;
              });
              draft = null;

              ejs.renderFile(
                path.resolve('./src/index.ejs' ),{
                  jsFile,cssFile,production,generatedContent,reduxState,title,description
                },{},function(err,str) {
                  if (err) {
                    console.log('error 3')
                    console.log(err);
                  }
                  response.status(200).send(str);
                });
            } else {
              console.log('error 4')
              console.log(err)
              error();
            }

          }).catch(err => {
            console.log('error 5')
            console.log(err)
            error();
          });

        } else {
          console.log('error 6')
          console.log(err)
          error();
        }
      });
    }
  })
});

index.ejs

<!DOCTYPE html>
<html lang="en">
  <head>
    <title><%- title %></title>
    <meta name="description" content="<%- description %>"/>
    <link href="<%- cssFile %>" rel="stylesheet"/>
    <script type="text/javascript" charset="utf-8">
      window.__REDUX_STATE__ = <%- reduxState %>;
    </script>
  </head>
  <body>
    <div id="root"><%- generatedContent %></div>
    <script type="text/javascript" src="<%- jsFile %>" defer></script>
  </body>
</html>

React组件中的示例fetchData函数

ExamplePage.fetchData = function (options) {
  const { store,at } = options

  return Promise.all([
    store.dispatch(exampleAction(params.id,ACTION_TYPE,userAccessToken))
  ]).spread(() => {
    let data = {
      SEO: {
        title: 'SEO Title',description: 'SEO Description'
      }
    }

    return Promise.resolve(data)
  })
}

解决方法

模块范围中定义的变量在整个运行时环境中只有一个副本.这意味着每个node.js进程都有自己的副本,每个浏览器选项卡/框架都有自己的副本.但是,在每个选项卡或每个进程中,只有一个副本.这意味着您无法将商店定义为模块级const,并且仍然为每个用??户创建一个新商店.你可以这样解决:

SRC / routes.js

import React from 'react';
import { createStore,compose } from "redux";
import routerConfig from "base/routes/routes";
import thunk from "redux-thunk";
import { rootReducer } from "base/reducers";

let initialState = {};

export function newUserEnv() {
  const store = createStore(
    rootReducer,compose(applyMiddleware(thunk))
  );

  const routes = routerConfig(store);
  return { store,routes };
}

server.js

import { newUserEnv } from 'routes';

let getReduxPromise = (renderProps,request) => {
  const { store } = newUserEnv();
  let { query,params } = renderProps
...

这为每个请求创建了一个新商店,并允许每个用户拥有自己的数据.请注意,如果您需要来自不同模块的相同商店,则需要传递它.您不能只导入{newUserEnv},因为它会创建一个新的.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读