使用 Axios transformRequest 导致 415 Unsupported Media Type
Using Axios transformRequest results in 415 Unsupported Media Type
我刚刚将我的 React 应用程序升级到 axios 0.25.0,并开始在某些 REST POST/PUT API 调用中收到 http 415 Unsupported Media type 错误。这些调用都有一个共同点,它们在请求中包含一个日期字段 body.
我使用 axios transformRequest 来确保任何日期字段都以本地时间发送到 API,而不是 JSON 默认的 UTC。
当我查看这些请求的 header 时,“Content-Type”已从“application/json”更改为“application/x-www-form-urlencoded”,随后被REST API 期望 [FromBody] JSON object。
我没有更改 API,而是添加了一个 axios 拦截器来确保 header“Content-Type”是“application/json”。这解决了问题,但我不喜欢这个修复。
转换请求
const serialiseDateLocal = (data: any) => {
Date.prototype.toJSON = function() {
// dateToString returns local time in specified format
return dateToString(this, "yyyy-MM-ddTHH:mm:ss.sssZ");
};
return JSON.stringify(data);
}
axios.defaults.transformRequest = [serialiseDateLocal];
拦截器
axios.interceptors.request.use(req => {
if(req.headers) {
req.headers["Content-Type"] = 'application/json';
}
return req;
});
为什么在使用转换时 content-type 变为“application/x-www-form-urlencoded”?有没有办法防止这种情况或更好的处理方式?
更新:
设置默认 headers 不需要拦截器。
axios.defaults.headers.common["Content-Type"] = "application/json";
axios.defaults.headers.post["Content-Type"] = "application/json";
axios.defaults.headers.put["Content-Type"] = "application/json";
axios.defaults.headers.patch["Content-Type"] = "application/json";
更新:
根据 Phils 的评论,问题原来是我 替换 transformRequest 链以及从我的转换器返回一个字符串 - 解决方案是。
const serialiseDateLocal: AxiosRequestTransformer = (data: any) => {
if (data instanceof Date) {
return dateToString(data, serializedFormat);
}
if (typeof data === "object" && data !== null) {
return Object.fromEntries(Object.entries(data).map(([ key, val ]) =>
[ key, serialiseDateLocal(val) ]))
}
return data;
}
axios.defaults.transformRequest = [serialiseDateLocal].concat(axios.defaults.transformRequest);
Axios 请求的 default content-type 是 application/x-www-form-urlencoded
。
default request transformer 做的一件事是为请求数据设置适当的 content-type...
if (utils.isObject(data) || (headers && headers['Content-Type'] === 'application/json')) {
setContentTypeIfUnset(headers, 'application/json');
return stringifySafely(data);
}
由于您要替换整个 transformRequest
链,您现在错过了这个。
你应该在你的变压器中处理它,例如
import { AxiosRequestTransformer } from "axios"
const serialiseDateLocal: AxiosRequestTransformer = (data, headers) => {
// TODO: actually transform the request, don't just modify the Date prototype
headers["Content-Type"] = "application/json"
return JSON.stringify(data)
}
或者更常见的是,将你的转换器移到现有链上并让它 return 成为一个普通的 object,让默认转换器完成它的工作
const instance = axios.create({
transformRequest: [ serialiseDateLocal ].concat(axios.defaults.transformRequest)
})
我还不确定为什么您的拦截器没有正确设置 header。我怀疑这是一个竞争条件,它可能值得 raising a bug report。
我刚刚将我的 React 应用程序升级到 axios 0.25.0,并开始在某些 REST POST/PUT API 调用中收到 http 415 Unsupported Media type 错误。这些调用都有一个共同点,它们在请求中包含一个日期字段 body.
我使用 axios transformRequest 来确保任何日期字段都以本地时间发送到 API,而不是 JSON 默认的 UTC。
当我查看这些请求的 header 时,“Content-Type”已从“application/json”更改为“application/x-www-form-urlencoded”,随后被REST API 期望 [FromBody] JSON object。 我没有更改 API,而是添加了一个 axios 拦截器来确保 header“Content-Type”是“application/json”。这解决了问题,但我不喜欢这个修复。
转换请求
const serialiseDateLocal = (data: any) => {
Date.prototype.toJSON = function() {
// dateToString returns local time in specified format
return dateToString(this, "yyyy-MM-ddTHH:mm:ss.sssZ");
};
return JSON.stringify(data);
}
axios.defaults.transformRequest = [serialiseDateLocal];
拦截器
axios.interceptors.request.use(req => {
if(req.headers) {
req.headers["Content-Type"] = 'application/json';
}
return req;
});
为什么在使用转换时 content-type 变为“application/x-www-form-urlencoded”?有没有办法防止这种情况或更好的处理方式?
更新: 设置默认 headers 不需要拦截器。
axios.defaults.headers.common["Content-Type"] = "application/json";
axios.defaults.headers.post["Content-Type"] = "application/json";
axios.defaults.headers.put["Content-Type"] = "application/json";
axios.defaults.headers.patch["Content-Type"] = "application/json";
更新: 根据 Phils 的评论,问题原来是我 替换 transformRequest 链以及从我的转换器返回一个字符串 - 解决方案是。
const serialiseDateLocal: AxiosRequestTransformer = (data: any) => {
if (data instanceof Date) {
return dateToString(data, serializedFormat);
}
if (typeof data === "object" && data !== null) {
return Object.fromEntries(Object.entries(data).map(([ key, val ]) =>
[ key, serialiseDateLocal(val) ]))
}
return data;
}
axios.defaults.transformRequest = [serialiseDateLocal].concat(axios.defaults.transformRequest);
Axios 请求的 default content-type 是 application/x-www-form-urlencoded
。
default request transformer 做的一件事是为请求数据设置适当的 content-type...
if (utils.isObject(data) || (headers && headers['Content-Type'] === 'application/json')) { setContentTypeIfUnset(headers, 'application/json'); return stringifySafely(data); }
由于您要替换整个 transformRequest
链,您现在错过了这个。
你应该在你的变压器中处理它,例如
import { AxiosRequestTransformer } from "axios"
const serialiseDateLocal: AxiosRequestTransformer = (data, headers) => {
// TODO: actually transform the request, don't just modify the Date prototype
headers["Content-Type"] = "application/json"
return JSON.stringify(data)
}
或者更常见的是,将你的转换器移到现有链上并让它 return 成为一个普通的 object,让默认转换器完成它的工作
const instance = axios.create({
transformRequest: [ serialiseDateLocal ].concat(axios.defaults.transformRequest)
})
我还不确定为什么您的拦截器没有正确设置 header。我怀疑这是一个竞争条件,它可能值得 raising a bug report。