当前位置: 首页 > 知识库问答 >
问题:

将参数从一个Axios请求传递到另一个Axios请求

戴凯歌
2023-03-14

出身背景

我将React Native中内置的应用程序连接到REST API。我通过Axios处理请求,并使用Redux存储查询结果。我有一个api连接的index.js文件,它保存了作为请求处理程序的函数,这些请求需要越来越深的授权级别。我有一个简单的函数返回访问令牌,这是由以下代码触发,当前位于应用程序的“欢迎页面”。

useEffect(() => {
    dispatch(retrieveToken());
  }, [dispatch]);

理想情况下,在浏览几个屏幕后,用户将进入主页并触发以下代码:

useEffect(() => {
    dispatch(retrieveData());
  }, [dispatch]);

到目前为止,一切顺利。以下是调度触发的功能:

 export const getToken = () =>
      apiInstance
        .request({
          url: ENDPOINTS.TOKEN,
          data: qs.stringify({
            grant_type: 'some_credentials',
            c_id: 'some_id',
            c_secret: 'some_secret',
          }),
          headers: {
            'content-type': 'some_content_type',
          },
          method: 'POST',
        })
        .then(response => {
          return response.data;
        })
        .catch(error => {
          return Promise.reject(error.message);
        });

export const getData = () =>
  apiInstance
    .request({
      url: ENDPOINTS.DATA,
      method: 'POST',
      data: qs.stringify({
        timestamp: Date.now(),
        c_id: 'some_id',
        token: **this is the token we get from the previous function**,
      }),
      headers: {
        'content-type': 'some_content_type',
      },
    })
    .then(response => {
      return response.data;
    })
    .catch(error => {
      return Promise.reject(error.message);
    });

问题

正如我前面提到的,这是一个Redux/Axios解决方案。这意味着状态是全局存储的,但有一个执行顺序。您应该注意到,这两个函数存储在同一个文件中,除非像我之前展示的两个分派调用那样明确说明,否则不会调用它们。

问题是,如果我从家中记录令牌(在使用dispatch调用它之后),我可以清楚地看到它,但是如果我尝试从存储请求函数的文件中记录所述令牌,我会得到一个空数组。我尝试用以下所有方法填充令牌字段:

  1. 常量状态=store.get状态()令牌:state.token
  2. const getData=(令牌)=

问题

如何从另一个axios查询中按特定顺序访问axios查询的结果?

非常重要的是要注意,API中的数据只能通过POST访问,执行getData()时得到的错误代码是401,不正确的凭据。另外,请记住这是一个Redux应用程序。查询的结果存储在全局状态中。然而,这种状态不能从外部组件访问,并且我不能从执行查询的文件中调用它,因为令牌“在那个时间点不存在”

动作码

import keyMirror from 'keymirror';
import {createAction} from 'redux-actions';
import {getToken} from '../../api';

export const tokenActionTypes = keyMirror({
  RETRIEVE_TOKEN_REQUEST: null,
  RETRIEVE_TOKEN_SUCCESS: null,
  RETRIEVE_TOKEN_FAILURE: null,
});

const tokenActionCreators = {
  request: createAction(tokenActionTypes.RETRIEVE_TOKEN_REQUEST),
  success: createAction(tokenActionTypes.RETRIEVE_TOKEN_SUCCESS),
  failure: createAction(tokenActionTypes.RETRIEVE_TOKEN_FAILURE),
};

export const retrieveToken = () => dispatch => {
  dispatch(tokenActionCreators.request());
  getToken()
    .then(token => dispatch(tokenActionCreators.success(token)))
    .catch(error => dispatch(tokenActionCreators.failure(error)));
};

减速机代码

import {tokenActionTypes} from '../actions/token';

export const initialState = {
  loadingToken: false,
  token: [],
  error: null,
};

const actionsMap = {
  [tokenActionTypes.RETRIEVE_TOKEN_REQUEST]: state => ({
    ...state,
    loadingToken: true,
  }),

  [tokenActionTypes.RETRIEVE_TOKEN_SUCCESS]: (state, action) => ({
    ...state,
    loadingToken: false,
    token: action.payload,
  }),

  [tokenActionTypes.RETRIEVE_TOKEN_FAILURE]: (state, action) => ({
    ...state,
    loadingToken: false,
    error: action.payload,
  }),
};

export default (state = initialState, action) => {
  const actionHandler = actionsMap[action.type];
  if (!actionHandler) {
    return state;
  }
  return actionHandler(state, action);
};

共有1个答案

谢俊英
2023-03-14

您可以将一个thunk组合到另一个thunk中,如将get token组合到get data中:

export const retrieveToken = () => (dispatch, getState) => {
  //you could use getState() to see if you need to fetch the token
  // const tokenResult = selectToken(getState());
  // if(token && !token expired) { return Promise.resolve() }
  dispatch(tokenActionCreators.request());
  //return a promise so you can wait for it
  return getToken()
    .then(token => dispatch(tokenActionCreators.success(token)))
    .catch(error => dispatch(tokenActionCreators.failure(error)));
};
//in retrieve data you can wait for the token
export const retrieveData = () => dispatch => {
  dispatch(retrieveToken()).then(
    ()=>{
      //here return getting the data
    }
  )
};

该代码中的一个可能的错误是,一个渲染周期将调度多个thunks,这些thunks将多次获得令牌。您可以通过将检索令牌操作与在解析时无效的缓存分组来解决这个问题:

const invalidateOnResolveCache = (cache = new Map()) => {
  return {
    get: (key) => cache.get(key),
    set: (key, value) => cache.set(key, value),
    resolved: (x) => cache.delete(key),
  };
};

或者,您可以为所有需要令牌的thunks编写包装函数:

//group retrieveToken in such a way that if it's called multiple times
//  during a render cycle the token request will only be made once
//https://gist.github.com/amsterdamharu/2dde4a6f531251f3769206ee44458af7
export const needsToken =
  (fn) =>
  (...args) =>
  (dispatch, getState) =>
    dispatch(retrieveToken(...args)).then(() =>
      //you could use getState to get the token and pass it to
      //  fn together with the other args
      // for example: fn(...args.concat(selectToken(getState())))
      fn(...args)
    );
export const autoTokenRetrieveData = needsToken(retrieveData);
//use needsToken for any other thunk actions that need a token

例子:

const { Provider, useDispatch, useSelector } = ReactRedux;
const { createStore, applyMiddleware, compose } = Redux;
const { createSelector } = Reselect;

//grouping code to group your actions
//group promise returning function
const createGroup =
  (cache) =>
  (fn, getKey = (...x) => JSON.stringify(x)) =>
  (...args) => {
    const key = getKey(args);
    let result = cache.get(key);
    if (result) {
      return result;
    }
    //no cache
    result = Promise.resolve(fn.apply(null, args)).then(
      (r) => {
        cache.resolved(key); //tell cache promise is done
        return r;
      },
      (e) => {
        cache.resolve(key); //tell cache promise is done
        return Promise.reject(e);
      }
    );
    cache.set(key, result);
    return result;
  };
//thunk action creators are not (...args)=>result but
//  (...args)=>(dispatch,getState)=>result
//  so here is how we group thunk actions
const createGroupedThunkAction = (thunkAction, cache) => {
  const group = createGroup(cache)(
    (args, dispatch, getState) =>
      thunkAction.apply(null, args)(dispatch, getState)
  );

  return (...args) =>
    (dispatch, getState) => {
      return group(args, dispatch, getState);
    };
};
const createInvalidateOnResolveCache = (
  cache = new Map()
) => {
  return {
    get: (key) => cache.get(key),
    set: (key, value) => cache.set(key, value),
    resolved: (key) => cache.delete(key),
  };
};
//function that fetches token
const uniqueToken = (
  (token) => () =>
    token++
)(1);
const fetchToken = () => Promise.resolve(uniqueToken());

const initialState = {
  data1: [],
  data2: [],
  token: null,
};
//action types
const DATA_SUCCESS = 'DATA_SUCCESS';
const GOT_TOKEN = 'GOT_TOKEN';
//action creators
const dataSuccess = (data, key) => ({
  type: DATA_SUCCESS,
  payload: { key, data },
});
const gotToken = (token) => ({
  type: GOT_TOKEN,
  payload: token,
});
const reducer = (state, { type, payload }) => {
  if (type === DATA_SUCCESS) {
    const { data, key } = payload;
    return {
      ...state,
      [key]: data,
    };
  }
  if (type === GOT_TOKEN) {
    return {
      ...state,
      token: {
        value: payload,
        created: Date.now(),
      },
    };
  }
  return state;
};
//thunk getting the data
const getData1 = (token) => (dispatch) =>
  Promise.resolve().then(() =>
    dispatch(
      dataSuccess(
        `got data 1 with token: ${token}`,
        'data1'
      )
    )
  );
const getData2 = (token) => (dispatch) =>
  Promise.resolve().then(() =>
    dispatch(
      dataSuccess(
        `got data 2 with token: ${token}`,
        'data2'
      )
    )
  );
//thunk getting the token:
const getToken = () => (dispatch) =>
  fetchToken().then((token) => dispatch(gotToken(token)));
//grouped thunk getting token
const getTokenGrouped = createGroupedThunkAction(
  getToken,
  createInvalidateOnResolveCache()
);
const needsToken =
  (fn) =>
  (...args) =>
  (dispatch, getState) => {
    let promise;
    //only fetch token if it's older than 1 second
    const tokenResult = selectToken(getState());
    if (
      tokenResult &&
      Date.now() - new Date(tokenResult.created).getTime() <
        1000
    ) {
      promise = Promise.resolve();
    } else {
      promise = dispatch(getTokenGrouped(...args));
    }
    return promise.then(() =>
      dispatch(
        fn(...args.concat(selectTokenValue(getState())))
      )
    );
  };
const getData1WithToken = needsToken(getData1);
const getData2WithToken = needsToken(getData2);
//selectors
const selectData1 = (state) => state.data1;
const selectData2 = (state) => state.data2;
const selectToken = (state) => state.token;
const selectTokenValue = createSelector(
  [selectToken],
  //SO snippet has no optional chaining, should just return token?.value
  (token) => token && token.value
);
//creating store with redux dev tools
const composeEnhancers =
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
  reducer,
  initialState,
  composeEnhancers(
    applyMiddleware(
      //simple thunk middleware
      ({ dispatch, getState }) =>
        (next) =>
        (action) =>
          typeof action === 'function'
            ? action(dispatch, getState)
            : next(action)
    )
  )
);
const Data1 = React.memo(function Data1({ refresh }) {
  const data = useSelector(selectData1);
  const dispatch = useDispatch();
  React.useEffect(() => {
    dispatch(getData1WithToken());
  }, [dispatch, refresh]);
  return <div>{data}</div>;
});
const Data2 = React.memo(function Data2({ refresh }) {
  const data = useSelector(selectData2);
  const dispatch = useDispatch();
  React.useEffect(() => {
    dispatch(getData2WithToken());
  }, [dispatch, refresh]);
  return <div>{data}</div>;
});
const App = () => {
  const [refresh, setRefresh] = React.useState({});
  return (
    <div>
      {/* getting data in one render cycle many times */}
      <Data1 refresh={refresh} />
      <Data2 refresh={refresh} />
      <Data1 refresh={refresh} />
      <Data2 refresh={refresh} />
      <Data1 refresh={refresh} />
      <Data2 refresh={refresh} />
      <button onClick={() => setRefresh({})}>
        refresh
      </button>
    </div>
  );
};

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
html prettyprint-override"><script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reselect/4.0.0/reselect.min.js"></script>
<script src="https://unpkg.com/immer@7.0.5/dist/immer.umd.production.min.js"></script>
<div id="root"></div>
 类似资料:
  • 问题内容: 我已经按照npm软件包文档中的建议编写了axios POST请求,例如: 它可以工作,但是现在我修改了后端API以接受标头。 内容类型:“ application / json” 授权:“ JWT fefege …” 现在,此请求在Postman上可以正常工作,但是在编写axios调用时,我遵循 此链接 ,无法完全正常工作。 我经常出错。 这是我的修改请求: 任何帮助是极大的赞赏。 问

  • 问题内容: 我需要链接来自Google Maps API的一些API请求,而我正在尝试使用Axios来实现。 这是第一个请求,它在componentWillMount()中 这是第二个请求: 然后,我们有第三个请求,这取决于前两个请求是否完成: 如何链接这三个电话,以便第三个电话发生在前两个电话之后? 问题答案: 首先,不确定是否要在其中执行此操作,最好将其插入并具有一些默认状态,这些状态一旦完成

  • 我正在构建一个VueJS应用程序,并使用JSON web令牌作为身份验证系统。当我登录用户时,我使用localStorage存储令牌,并且工作正常。我检查了标题,它在“授权”参数中。 我通过 我看到了标题,没关系。但是,当我对API中的受保护路由执行get请求时,返回“unauthorized”。但是,当我在请求中手动传递带有令牌的标头时,效果很好。 有人知道如何在执行某个请求时自动传递头吗?

  • 问题内容: 我正在开发一个React应用,该应用需要从elsaticsearch获取数据。在前端,实际上我正在尝试使用axios来执行请求: 我想获取带有某些ID的特定文档。上面的查询实际上在kibana内部有效。但是,以上查询返回my-type内的所有文档,我在这里做错了什么? 问题答案: 我认为以下应该可行。虽然爱可信自述说,是专门只为,,和请求,我没有看到在强制执行此代码的任何,和简化的测试

  • 我一直在使用响应模板来提供动态响应,因为所有请求和查询参数都与该请求本身相关联。但是,我想使用多个参数发出 POST 请求,然后通过使用响应模板在存根 GET 方法的正文响应中使用这些参数。这在电线中可以做些什么吗?任何输入都非常感谢,谢谢!

  • 问题内容: 因此,我一直将以下代码放入我的React JS组件中,而我基本上是试图将两个API调用都置于一种称为的状态,但是以下代码却出现了错误: 现在,我猜我无法像我一样添加两个数据源,但是还可以怎么做呢?我只希望将来自该API请求的所有数据置于一种状态。 这是我目前收到的错误: 谢谢 问题答案: 您不能将数组“添加”在一起。使用array.concat函数(https://developer.