如何在同构React应用程序的服务器端数据获取中访问cookie

时间:2018-08-23 22:37:58

标签: javascript reactjs express redux isomorphic-javascript

我正在构建一个同构/通用的React + Redux + Express应用程序。我的服务器端数据获取是非常标准的:我看到哪些路由与URL匹配,调用所有都返回诺言的相关数据获取方法,然后等待它们解析并呈现HTML。

我的挑战:一些API调用需要auth。登录的用户有一个cookie,它当然会随每个请求一起发送。但是,当我在服务器端进行数据提取以填充存储以进行初始渲染时,该cookie对我的API调用不可用。我如何做到这一点?

// server-entry.jsx
app.get('*', (req, res) => {
  const store = createStore(
    combineReducers({
      // lots of reducers
    }),
    {},
    applyMiddleware(thunk),
  );
  /*
    The contents of getDataFetchers isn't important. All you need
    to know is it returns an array of data-fetching promises like so:

    dispatch(thunkAction());
  */
  const fetchers = getDataFetchers(req.url, store);

  Promise.all(fetchers).then(() => {
    // render the tree
  });
});

// one of my thunk actions hits an API endpoint looking like this:
app.get('/api', (req, res) => {
  // this is simplified, but you get the idea:
  // we need access to the cookie to authenticate
  // but when this call is made server-side, req.session.user doesn't exist
  if (!req.session.user) res.status(403);
  else res.json({ data: 'here' });
});

我想我可以从req的{​​{1}}处获取cookie,并将它作为参数一直传递到实际数据获取(用axios完成),在该位置用app.get标头指定。但这感觉很糟糕。

1 个答案:

答案 0 :(得分:2)

您的建议是正确的,如果您希望服务器端HTTP请求包含原始请求的cookie,则需要以允许其访问以下内容的方式构造HTTP客户端(在您的情况下为axios)标头是在实例化时还是在发出每个请求之前。

Here is a link to how Apollo does it.

import { ApolloProvider } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import Express from 'express';
import { StaticRouter } from 'react-router';
import { InMemoryCache } from "apollo-cache-inmemory";

import Layout from './routes/Layout';

// Note you don't have to use any particular http server, but
// we're using Express in this example
const app = new Express();
app.use((req, res) => {

  const client = new ApolloClient({
    ssrMode: true,
    // Remember that this is the interface the SSR server will use to connect to the
    // API server, so we need to ensure it isn't firewalled, etc
    link: createHttpLink({
      uri: 'http://localhost:3010',
      credentials: 'same-origin',
      headers: {
        cookie: req.header('Cookie'),
      },
    }),
    cache: new InMemoryCache(),
  });

  const context = {};

  // The client-side App will instead use <BrowserRouter>
  const App = (
    <ApolloProvider client={client}>
      <StaticRouter location={req.url} context={context}>
        <Layout />
      </StaticRouter>
    </ApolloProvider>
  );

  // rendering code (see below)
});

如您所见,ApolloClient已创建,并在实例化时传递了初始请求的cookie。