使用 Axios 将数据传递到服务

3

我想在头部设置_boundry

首先,我要发送表单数据:

//component.js

const form = new FormData();

form.append('email', 'eray@serviceUser.com')
form.append('password', '12121212')

dispatch(FetchLogin.action(form))

其次,我准备 API 调用;

//loginService.js

import api from '@/Services'

export default async form => {
  const response = await api.post('user/login/', form)
  return response.data
}

第三步,我进行 API 调用。

//Services/index.js

import axios from 'axios'
import { Config } from '@/Config'

const instance =  axios.create({
  baseURL: Config.API_URL,
  headers: {
    'Content-Type': `multipart/form-data; boundary=${form._boundary}`, //Cannot access form here
  }, 
  timeout: 3000,
})

instance.interceptors.response.use(
  response => response,
  ({ message, response: { data, status } }) => {
    return handleError({ message, data, status })
  },
)

export default instance

我希望能够在axios实例中访问form数据,以便在headers中使用form._boundry。请问如何将loginService.js中的form数据传递到Services/index.js中?

1个回答

6

当从浏览器(通过fetchXMLHttpRequest)执行AJAX请求时,运行时知道如何处理某些请求正文格式,并将自动设置适当的Content-type头。

  • 如果请求体是一个FormData实例,则Content-type将被设置为multipart/form-data,并且还将包括来自数据实例的适当mime分界符令牌。

    所有这些示例都将以适当的 mime分界符作为 multipart/form-data 发送数据

    const body = new FormData();
    
    // 附加文件和其他字段
    body.append("file", fileInput.files[0]);
    body.append("foo", "foo");
    body.append("bar", "bar");
    
    // fetch
    fetch(url, { method: "POST", body });
    
    // XMLHttpRequest
    const xhr = new XMLHttpRequest();
    xhr.open("POST", url);
    xhr.send(body);
    
    // Axios
    axios.post(url, body);
    
  • 如果请求体是一个URLSearchParams实例,则Content-type将被设置为application/x-www-form-urlencoded

    所有这些示例都将作为application/x-www-form-urlencoded发送数据

    const body = new URLSearchParams({ foo: "foo", bar: "bar" });
    // 序列化为"foo=foo&bar=bar"
    
    // fetch
    fetch(url, { method: "POST", body });
    
    // XMLHttpRequest
    const xhr = new XMLHttpRequest();
    xhr.open("POST", url);
    xhr.send(body);
    
    // Axios
    axios.post(url, body);
    
您只需要在打算以特定格式发送字符串数据时手动设置content-type,例如text/xmlapplication/json等,因为运行时无法从数据中推断出类型。
const body = JSON.stringify({ foo: "foo", bar: "bar" });

// fetch
fetch(url, {
  method: "POST",
  headers: {
    "content-type": "application/json",
  },
  body
});

// XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.setRequestHeader("content-type", "application/json");
xhr.send(body);

关于 Axios

Axios 会自动将传入 data 参数的 JavaScript 数据结构转换为字符串,并将 Content-type 头设置为 application/json,因此在处理 JSON API 时只需要进行最小配置。

// no extra headers, no JSON.stringify()
axios.post(url, { foo: "foo", bar: "bar" })

Axios在底层使用XMLHttpRequest,因此FormDataURLSearchParams的规范也适用。

Axios v0.27.1已损坏

这个特定版本的Axios无法使用FormData进行正确的请求。不要使用它!

Axios v1.0.0+已损坏

这是我的个人意见,但自v1.0.0以来的每个Axios发布都在某种程度上存在根本性的问题。我不能建议任何人出于任何原因使用它。

更好的替代方案包括:

  • Fetch API(也可在Node v18+中使用)
  • got 用于Node.js
  • ky 用于浏览器

NodeJS

当从后端使用Axios时,它将无法从FormData实例推断出Content-type头。您可以使用请求拦截器解决此问题。

axios.interceptors.request.use(config => {
  if (config.data instanceof FormData) {
    Object.assign(config.headers, config.data.getHeaders());
  }
  return config;
}, null, { synchronous: true });

或者在发出请求时直接合并头部信息

axios.post(url, body, {
  headers: {
    "X-Any-Other-Headers": "value",
    ...body.getHeaders(),
  },
});

请查看 https://github.com/axios/axios#form-data


关于jQuery $.ajax()

jQuery的$.ajax()方法(以及像$.post()这样的便捷方法)默认将请求体负载发送为application/x-www-form-urlencoded。除非告诉它不要这样做,否则JavaScript数据结构将自动使用jQuery.param()进行序列化。如果您希望浏览器根据正文格式自动设置Content-type头,则还需要在选项中进行配置。

const body = new FormData()
body.append("foo", "foo")
body.append("bar", "bar")

$.ajax({
  url,
  method: "POST",
  data: body,
  contentType: false, // let the browser figure it out
  processData: false  // don't attempt to serialise data
})

谢谢您详细的回答。我看到您提到在Axios中不需要定义头部,这太好了!但是您的回答并没有解决我的问题。我仍然无法正确地发布formData。如果我在组件中像您的回答一样不带header发布formData,一切都很好。但是如果我使用dispatch formDataAxios会使用默认头部进行发布:"Content-Type": "application/x-www-form-urlencoded"。问题可能与Redux有关。 - ilvthsgm
@ilvthsgm 非常奇怪。您能否编辑您的问题以显示如何连接您的reducers和任何中间件(sagas / thunks /等)?请让我们看看。 - Phil
1
我的URL中有多余的“/”,这就是问题所在。感谢您的帮助。 - ilvthsgm
1
对于任何对规范的感兴趣的人,这里提供一个加分项:要求浏览器为URLSearchParamsFormData设置Content-Type头,请参见此处的第6项。 - Eric Mutta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接