0

我的项目使用 Next.js、redux 和 redux saga。以及 Axios 来管理 redux saga 的 XHR 请求。

在我的自定义应用程序(见下文)getInitialProps中,我设置了 Axios 在客户端和服务器上发出请求时使用的基本 url。看起来这对于服务器来说工作正常(没有错误)。但是,客户端上的请求最终会尝试https://undefined/...用作请求 url:

在此处输入图像描述

以下是我的相关代码,从自定义应用程序开始,一直使用 Axios 跟踪到 root saga 设置。任何指针将不胜感激。

// _app.tsx

function MyApp({
    Component,
    pageProps,
    apiBaseUrl,
    cookie,
  }: AppProps & CustomAppProps) {
    const store = useStore(pageProps.initialReduxState, { apiBaseUrl, cookie });
  
      return (
        <>
          <Head>
            <title>{formatTitle(storeEntity)}</title>  
          </Head>
          <Provider store={store}>
              <Component {...pageProps} />
          </Provider>
        </>
      )
  }
  
  MyApp.getInitialProps = async (appContext: {
    ctx: AppContext;
  }): Promise<CustomAppProps> => {
    let cookie: string;
    let apiBaseUrl: string;
  
    if (appContext.ctx.req) {
      cookie = appContext.ctx.req.headers.cookie || '';
      const host = appContext.ctx.req.headers['codomain'];
      apiBaseUrl = `https://${host}/api`;
    } else {
      cookie = '';
      apiBaseUrl = `${window.location.origin}/api`;
    }
  
    let appProps = await App.getInitialProps(appContext as any);
  
    return {
      ...appProps,
      cookie,
      apiBaseUrl,
    };
  };
  
  export default appWithTranslation(MyApp as any);
// use-store.tsx


function initStore(
  preloadedState: StoreState,
  { apiBaseUrl, cookie }: CustomAppProps,
) {
  const store = createStore(
    reducer,
    preloadedState,
    composeWithDevTools(applyMiddleware(sagaMiddleware)),
  );

  sagaMiddleware.run(rootSaga.bind(null, { apiBaseUrl, cookie }));

  return store;
}

export const initializeStore = (
  preloadedState: StoreState,
  { apiBaseUrl, cookie }: CustomAppProps,
): Store<StoreState, StoreAction> & {
  dispatch: unknown;
} => {
  let _store = store ?? initStore(preloadedState, { apiBaseUrl, cookie });

  // After navigating to a page with an initial Redux state, merge that state
  // with the current state in the store, and create a new store
  if (preloadedState && store) {
    _store = initStore(
      {
        ...store.getState(),
        ...preloadedState,
      },
      { apiBaseUrl, cookie },
    );

    store = undefined;
  }

  // For SSG and SSR always create a new store
  if (typeof window === 'undefined') {
    return _store;
  }

  // Create the store once in the client
  if (!store) {
    store = _store;
  }

  return _store;
};

export function useStore(
  initialState: StoreState,
  { apiBaseUrl, cookie }: CustomAppProps,
) {
  const store = useMemo(
    () => initializeStore(initialState, { apiBaseUrl, cookie }),
    [initialState],
  );

  return store;
// rootSaga.ts

function* rootSaga({ apiBaseUrl, cookie }: CustomAppProps) {
  const Api = new ApiService(AxiosWithApi({ apiBaseUrl, cookie }));

  // We need to bind handlers to give them the 'Api' method
  const fetchStoreBound = fetchStore.bind(null, Api);
  
  yield takeLatest('API/GET_STORE', fetchStoreBound);
}
// api.tsx

export function AxiosWithApi({ cookie, apiBaseUrl }: CustomAppProps) {
    const axiosOptions: AxiosRequestConfig = {
      withCredentials: true,
    };
  
    return Axios.create(axiosOptions);
}
  
export class ApiService {
  constructor(private readonly http: AxiosInstance) {}

// ...
}
4

0 回答 0