在第二个 axios api 调用上获取错误 400 错误请求

Posted

技术标签:

【中文标题】在第二个 axios api 调用上获取错误 400 错误请求【英文标题】:GET error 400 bad request on second axios api call 【发布时间】:2020-02-14 19:23:39 【问题描述】:

我正在尝试使用 Axios 从 API 获取数据。我有两个 API 调用。第一次通话运行良好,我得到了我期望的数据。但是,第二个返回 400 错误错误请求。

我已经搜索了多个论坛以尝试找到解决方案,但我不太了解我找到的代码。

    const [player, setPlayer] = useState([]);
    const [newPlayer, setNewPlayer] = useState([]);

    const FindLoadout = async () => 
        await axios.get(`http://api.paladins.com/paladinsapi.svc/getmatchidsbyqueueJson/$devId/$generateSignature('getmatchidsbyqueue')/$props.sess/$moment.utc().format('YYYYMMDDHHmmss')/428/$moment.utc().format('YYYYMMDD')/-1,00`).then((response) => 
                const playerData = response.data;
                playerData.map((el) => 
                    player.push(el.Match)
                )
                console.log(player);
                for(let i = 0; i < 50; i++) 
                    newPlayer.push(player[i]);
                
                console.log(newPlayer);
            ).catch((error) => 
                console.log(error);
            );
            axios.get(`http://api.paladins.com/paladinsapi.svc/getmatchdetailsbatchJson/$devId/$generateSignature('getmatchdetailsbatch')/$props.sess/$moment.utc().format('YYYYMMDDHHmmss')/$newPlayer.join(",")`).then((response) => 
                console.log(response);
            ).catch((error) => 
                console.log(error);
            );
    

错误信息是:

错误:请求失败,状态码 400 在 createError (createError.js:17) 定居时 (settle.js:19) 在 XMLHttpRequest.handleLoad (xhr.js:60)

【问题讨论】:

代码示例不完整:playernewPlayer 未定义。 已编辑,谢谢。 不确定这是否是这里唯一的问题,因为这是非常特定于 API 的,并且您没有包含 generateSignature 等的代码,但是您没有正确使用 useState 挂钩.它返回的第二个值是它应该如何更新,例如:setPlayer(myUpdatedValue):reactjs.org/docs/hooks-state.html 【参考方案1】:

我不知道它是否能完全解决您的问题,但是当使用 async / await 获取数据时,通常的做法是更像这样:

const FindLoadout = async () => 

  const playerData= await axios
    .get(`http://api.paladins.com/player/154`)
    .then(response => response.data);

  const gameData= await axios
    .get(`http://api.paladins.com/game/788`)
    .then(response => response.data);

  return player: playerData, game: gamedata

也就是说,您将 API 调用获取的数据分配给变量,然后返回您需要的数据(经过您认为的任何操作必要)。

以这种同步语法编写异步代码的能力是async / await 最吸引人的特点之一。

我怀疑您收到的错误是因为您的第二次调用在触发之前没有 await 关键字。

编辑:另外,正如其他人所说,你肯定会遇到不正确使用钩子的问题,但这不是问题的范围。

【讨论】:

这样做似乎因为某种原因破坏了我的代码。甚至以前的 API 调用也不再有效。我按照您上面提到的相同方式设置它们。编辑:它实际上并没有破坏它,只是让它需要更长的时间。但是,我仍然收到 400 错误。 你能尝试通过钩子移除状态管理,只触发 API 调用,将返回的数据分配给变量,并记录这些变量吗?只是为了有这个错误的最小例子。 400 错误可能意味着您为其中一个 API 调用提供了错误的路径。 只需要等待第一个呼叫。第二个是简单地使用then 进行日志记录。但是,是的,await 而不是 then 更好:) 好吧,即使它只是记录响应,它仍然会触发 API 调用,因此本质上是一段异步代码,应该是 awaited。除非我从根本上误解了什么。【参考方案2】:

首先,你混合了异步和传统的 Promise

[编辑:你也直接改变状态而不是使用 setState]

[EDIT2:设置状态不是立即的,因此在 setState 之后直接设置状态的 console.log(以及依赖于状态值的 axios 获取请求)通常不会记录您预期的值,因此应该包含在回调中传递给 setState 的函数 - 或 - 在状态更新时使用 useEffect]

[EDIT3:在循环之外构建新状态,然后在 setState 之后]

const [player, setPlayer] = useState([]);
const [newPlayer, setNewPlayer] = useState([]);
const FindLoadout = async () => 
    useEffect(()=>
        if (!player.length) return
        const newState = [...newPlayer]
        for(let i = 0; i < 50; i++) 
            newState.push(player[i]);
        
        setNewPlayer(newState)
    , [player]);
    useEffect(() => 
        if (!newPlayer.length) return 
         axios
            .get(`http://api.paladins.com/paladinsapi.svc/getmatchdetailsbatchJson/$devId/$generateSignature('getmatchdetailsbatch')/$props.sess/$moment.utc().format('YYYYMMDDHHmmss')/$newPlayer.join(",")`)
            .then((gameData)=>
                console.log(gameData)
            ).catch((error)=>
                console.error(error)
            )
    , [newPlayer]);
    try 
        const playerData= await axios.get(`http://api.paladins.com/paladinsapi.svc/getmatchidsbyqueueJson/$devId/$generateSignature('getmatchidsbyqueue')/$props.sess/$moment.utc().format('YYYYMMDDHHmmss')/428/$moment.utc().format('YYYYMMDD')/-1,00`)
        const newState = [...player]
        playerData.map((el) => newState.push(el.Match))
        setPlayer(newState)
    catch(error) 
        console.error(error);
     

如果你想在第二个 useEffect 中坚持使用 asyc,你也可以使用回调来代替: https://dev.to/n1ru4l/homebrew-react-hooks-useasynceffect-or-how-to-handle-async-operations-with-useeffect-1fa8

useEffect(() => 
        if (!newPlayer.length) return
        const myCallback = async ()=>
            try
                const gameData = await axios.get(`http://api.paladins.com/paladinsapi.svc/getmatchdetailsbatchJson/$devId/$generateSignature('getmatchdetailsbatch')/$props.sess/$moment.utc().format('YYYYMMDDHHmmss')/$newPlayer.join(",")`)
                console.log(gameData)
            catch(error)
                console.error(error)
            
        
        myCallback()
, [newPlayer]);

如果这不能解决问题:

400 Bad Request 错误是一个 HTTP 状态代码,表示 您发送到网站服务器的请求不知何故不正确或已损坏,服务器无法理解。

ie:您的 API 调用的 URL 不正确 我会仔细检查“generateSignature”函数是否返回正确的值。如果是这种情况,我会检查以确保 newPlayer.join(",") 返回正确的值。

【讨论】:

我将异步函数更改为您在此处介绍的方式。我检查了我提供给 URL 的所有变量,它们看起来都正确。我尝试在 join 方法中输入 %5C%2C 和 %2C 。这给了我 404 错误,未找到。 请检查我当前的编辑:您没有正确设置状态,并且您在设置后尝试直接访问状态 再次编辑以包含 useEffect,这是一种比 setState 回调更简洁的方法 我也不确定你是否有意,但你的 newPlayer 状态最终会有很多重复项(每次添加玩家时,你都会将每个玩家添加到 newPlayer 数组中,即使它已经存在) 这给了我一个错误,说我不能在异步函数之外使用“等待”。就像您在上面的代码中一样,我将它们嵌套。 newPlayer 也是从播放器数组中获取更小的数据样本。【参考方案3】:

我认为问题在于您如何将值分配给 playernewPlayer。由于您使用的是useState 钩子,因此您应该使用setPlayersetNewPlayer

你能告诉我在第二次 api 调用之前newPlayer 的值是多少吗?

也许你可以这样更新它:

const FindLoadout = async () => 
        await axios.get(`http://api.paladins.com/paladinsapi.svc/getmatchidsbyqueueJson/$devId/$generateSignature('getmatchidsbyqueue')/$props.sess/$moment.utc().format('YYYYMMDDHHmmss')/428/$moment.utc().format('YYYYMMDD')/-1,00`).then((response) => 
                const playerData = response.data;
                //playerData.map((el) => 
                //    player.push(el.Match)
                //)
                setPlayer(playerData.map(el) => el.Match);
                console.log(player);
                //for(let i = 0; i < 50; i++) 
                //    newPlayer.push(player[i]);
                //
                // I'm not sure how to update this assignment
                console.log(newPlayer);
            ).catch((error) => 
                console.log(error);
            );
            axios.get(`http://api.paladins.com/paladinsapi.svc/getmatchdetailsbatchJson/$devId/$generateSignature('getmatchdetailsbatch')/$props.sess/$moment.utc().format('YYYYMMDDHHmmss')/$newPlayer.join(",")`).then((response) => 
                console.log(response);
            ).catch((error) => 
                console.log(error);
            );
    

关于更新newPlayer:由于状态是异步更新的,当您尝试使用player 中的值更新newPlayer 时,player 中没有任何内容。

尝试使用一些硬编码的值发出请求,看看问题出在 api 请求还是变量中的值。

【讨论】:

以上是关于在第二个 axios api 调用上获取错误 400 错误请求的主要内容,如果未能解决你的问题,请参考以下文章

从 Axios API 返回数据

无法在第二个视图控制器中更新我的 UIImage

将两个反应 API 链接在一起,其中一个的输出进入第二个的输入。使用 Axios/Async

如何使用 Azure REST API 从管道中获取所有变量?

React Axios API 调用与数组循环给出错误的顺序?

如何为调用 API 的方法编写 JUnit 测试?