Fetch API与Axios API的比较

huangapple go评论71阅读模式
英文:

Fetch Api vs Axios Api

问题

如果我在React.js前端使用fetch请求发送API请求,并尝试在fetch请求中添加body,浏览器会抛出错误:

Uncaught (in promise) TypeError: Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body

但是,如果我使用Axios而不是fetch API来进行GET请求,这里使用的是data字段而不是fetch API的body。如果在data字段中放入内容并发送GET请求,浏览器不会抛出错误,但服务器将无法在请求的body中获取任何内容。另一个奇怪的行为是,在具有值的data字段的Axios GET请求中,浏览器还会发送CORS预检请求,这很奇怪,因为这是一个GET请求。

使用Axios

以下是使用存储在httpOnly cookie中的刷新令牌生成新访问令牌的代码。这是一个Axios GET请求。

没有Data字段

代码

const response = (
  await axios.request<AuthType>({
    url: "http://192.168.1.34:4488/webadmin/generatenewaccesstoken",
    method: "GET",
    withCredentials: true,
  })
).data;

浏览器网络选项卡

Fetch API与Axios API的比较

使用Data字段

如果我将Axios GET请求更改为在空对象中包含data,浏览器将为此Axios请求发送预检。

代码

const response = (
  await axios.request<AuthType>({
    url: "http://192.168.1.34:4488/webadmin/generatenewaccesstoken",
    method: "GET",
    withCredentials: true,
    data: {}
  })

浏览器网络选项卡

以下图像是浏览器的网络选项卡,您可以看到即使请求方法仍为GET,也会发送预检。
Fetch API与Axios API的比较

使用Fetch

没有body字段

代码

let response = await (
  await fetch("http://192.168.1.34:4488/webadmin/generatenewaccesstoken", {
    method: "GET",
    credentials: "include",
  })
).json();

浏览器网络选项卡

Fetch API与Axios API的比较

使用body字段

代码

let response = await (
  await fetch("http://192.168.1.34:4488/webadmin/generatenewaccesstoken", {
    method: "GET",
    credentials: "include",
    body: JSON.stringify({}),
  })
).json();

浏览器网络选项卡

Fetch API与Axios API的比较

当使用Axios时,如果我们在GET请求中包含data字段,即使请求方法为'GET',浏览器也会发送预检。但是,当使用将方法设置为'GET'的fetch API并尝试包含body字段时,浏览器将不发送任何内容。另外,我正在使用Edge浏览器。

从上面的内容中,我推断Axios的data不仅仅是对axios的body的抽象,这两者之间存在根本的区别。有人可以告诉我我的推断是否正确,并解释这种行为的原因吗?

P.S

另外,如果我们将上述端点的方法类型更改为'POST',并且无论我们使用axios还是fetch API,如果我们在fetch API的情况下发送不带body字段的POST请求,或者在axios的情况下发送不带data字段的POST请求,预检请求都不会被发送。根据我阅读的文章和文档,我了解到,如果请求不是'GET'或'OPTION',则会发送预检请求。但在这种情况下,仅仅一个'POST'请求不会发送预检请求,它应该包含一个body或data,以便浏览器发送预检请求。

英文:

If i use fetch request to send API request from my react js front end and if i tried to put body in the fetch request. the browser will throw error saying

Uncaught (in promise) TypeError: Failed to execute &#39;fetch&#39; on &#39;Window&#39;: Request with GET/HEAD method cannot have body

But if i use Axios instead of fetch API to make the get request, here there is data field instead of body of fetch API. and if put something in the data field and send the get request, browser does not throw error. but the server will not get anything in the body of request.Another strange behavior is that in this Axios get request with data field having value,browser also sends a CORS preflight request which is strange because this is a get request.

Using Axios

The following is the code to generate new access token using refresh token stored in httpOnly cookie.This is axios get request

Without Data Field

Code

    const response = (
      await axios.request&lt;AuthType&gt;({
        url: &quot;http://192.168.1.34:4488/webadmin/generatenewaccesstoken&quot;,
        method: &quot;GET&quot;,
        withCredentials: true,
      })
    ).data;

Browser Network Tab

Fetch API与Axios API的比较

With Data Field

If i change the axios get request to include data with empty object the browser will send a preflight for this axios request.

Code

    const response = (
      await axios.request&lt;AuthType&gt;({
        url: &quot;http://192.168.1.34:4488/webadmin/generatenewaccesstoken&quot;,
        method: &quot;GET&quot;,
        withCredentials: true,
        data:{}
      })

Browser Network Tab

the following image is the browser's network tab and you can see that preflight is sent even though the request method is still GET
Fetch API与Axios API的比较

Using Fetch

without body field

Code

    let response = await (
      await fetch(&quot;http://192.168.1.34:4488/webadmin/generatenewaccesstoken&quot;, {
        method: &quot;GET&quot;,
        credentials: &quot;include&quot;,
      })
    ).json();

Browser Network Tab

Fetch API与Axios API的比较

With body field

Code

    let response = await (
      await fetch(&quot;http://192.168.1.34:4488/webadmin/generatenewaccesstoken&quot;, {
        method: &quot;GET&quot;,
        credentials: &quot;include&quot;,
        body: JSON.stringify({}),
      })
    ).json();

Browser Network Tab

Fetch API与Axios API的比较

when using axios,if we include data field in the get request, the browser sends preflight for the request even though request method is 'GET'. but when using fetch Api with method set to 'GET if we try to include the body field. the browser will send nothing. Also I'am using edge browser

From the above, I' am inferring that data of Axios is not just a abstraction of body of axios, there is a fundamental difference in these two. Can someone tell me if my inference is correct and explain the reason for this behavior .

P.S

Also if we change the above endpoint method type to 'POST'. and whatever we are using axios or fetch api. if we are sending the post request without body field in the case of fetch api or without data field in the case of axios, the preflight request will not be send. From articles and documentation i have read,what i understood was if the request is request other than 'GET' or 'OPTION' a preflight request will be send. but in this case preflight will not be send for just a 'POST' request, it should contain a body or data for the browser to send preflight.

答案1

得分: 2

不能在GET请求中设置请求体。

如果你使用fetch尝试这样做,它会向你报错。

如果你使用XMLHttpRequestaxios是其封装器)尝试这样做,它会忽略你的无效操作。


当你在HTTP请求中设置请求体时,你需要指定该请求体的Content-Type(除非你使用某种机制可以推断出它)。

axiosdata参数中传递一个对象将会使axiosContent-Type设置为application/json

带有Content-Type: application/json的跨域请求需要进行预检请求。

XMLHttpRequest不会忽略axios设置的Content-Type,但它会忽略axios设置的请求体。

这将导致进行预检请求,如果成功,将会发送一个带有内容类型但没有请求体的真实请求。

英文:

You may not set a body on a GET request.

If you try to do that with fetch then it will complain at you.

If you try to do that with XMLHttpRequest (which axios is a wrapper around) then it will ignore your nonsense.


When you set a body on an HTTP request, you need to specify the Content-Type of that body (unless you set it using a mechanism which from which it can be inferred).

Passing an object to data on axios will make axios set the Content-Type to application/json.

Cross-origin requests with Content-Type: application/json require a preflight request.

XMLHttpRequest won't ignore axios setting the Content-Type but it will ignore axios setting the request body.

This results in a preflighted request which, if successful, will make the real request with a content-type but no content in the body.

答案2

得分: 1

MDN很好地解释了CORS的工作原理,什么是简单请求,以及哪些请求需要预检请求

GET请求不能有请求体,但可以在URL中包含查询参数。
POST请求也可以在URL中包含查询参数,同时也可以有一个(可选的)请求体。
即使你向Axios提供了data,如果请求是GET,Axios也不会添加请求体到XHR中。

英文:

MDN explains pretty well how CORS works, what is a simple request and which requests need preflight

GET requests can not have a body - but they can have query parameters in the URL.
POST requests can have query parameters in the URL, too - but they also can have a body (optionally).
Even if you provide data to Axios - if the request is GET then Axios will not add a body to the XHR.

huangapple
  • 本文由 发表于 2023年8月9日 14:59:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76865322.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定