mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-24 20:24:05 -08:00
🐛 Improve Axios compatibility (#2262)
* Improved the error object returned by axios to make it more compatible with request
* Fixed multipart/form-data payload creation
* 🐛 Remove issue with circular references
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
This commit is contained in:
parent
04a043616e
commit
4a3d3cd331
|
@ -91,6 +91,33 @@ const requestPromiseWithDefaults = requestPromise.defaults({
|
||||||
timeout: 300000, // 5 minutes
|
timeout: 300000, // 5 minutes
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const pushFormDataValue = (form: FormData, key: string, value: any) => {
|
||||||
|
if (value?.hasOwnProperty('value') && value.hasOwnProperty('options')) {
|
||||||
|
// @ts-ignore
|
||||||
|
form.append(key, value.value, value.options);
|
||||||
|
} else {
|
||||||
|
form.append(key, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const createFormDataObject = (data: object) => {
|
||||||
|
const formData = new FormData();
|
||||||
|
const keys = Object.keys(data);
|
||||||
|
keys.forEach((key) => {
|
||||||
|
// @ts-ignore
|
||||||
|
const formField = data[key];
|
||||||
|
|
||||||
|
if (formField instanceof Array) {
|
||||||
|
formField.forEach((item) => {
|
||||||
|
pushFormDataValue(formData, key, item);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
pushFormDataValue(formData, key, formField);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return formData;
|
||||||
|
};
|
||||||
|
|
||||||
async function parseRequestObject(requestObject: IDataObject) {
|
async function parseRequestObject(requestObject: IDataObject) {
|
||||||
// This function is a temporary implementation
|
// This function is a temporary implementation
|
||||||
// That translates all http requests done via
|
// That translates all http requests done via
|
||||||
|
@ -139,28 +166,12 @@ async function parseRequestObject(requestObject: IDataObject) {
|
||||||
if (requestObject.formData !== undefined && requestObject.formData instanceof FormData) {
|
if (requestObject.formData !== undefined && requestObject.formData instanceof FormData) {
|
||||||
axiosConfig.data = requestObject.formData;
|
axiosConfig.data = requestObject.formData;
|
||||||
} else {
|
} else {
|
||||||
const allData = Object.assign(requestObject.body || {}, requestObject.formData || {});
|
const allData = {
|
||||||
|
...(requestObject.body as object | undefined),
|
||||||
|
...(requestObject.formData as object | undefined),
|
||||||
|
};
|
||||||
|
|
||||||
const objectKeys = Object.keys(allData);
|
axiosConfig.data = createFormDataObject(allData);
|
||||||
if (objectKeys.length > 0) {
|
|
||||||
// Should be a standard object. We must convert to formdata
|
|
||||||
const form = new FormData();
|
|
||||||
|
|
||||||
objectKeys.forEach((key) => {
|
|
||||||
const formField = (allData as IDataObject)[key] as IDataObject;
|
|
||||||
if (formField.hasOwnProperty('value') && formField.value instanceof Buffer) {
|
|
||||||
let filename;
|
|
||||||
// @ts-ignore
|
|
||||||
if (!!formField.options && formField.options.filename !== undefined) {
|
|
||||||
filename = (formField.options as IDataObject).filename as string;
|
|
||||||
}
|
|
||||||
form.append(key, formField.value, filename);
|
|
||||||
} else {
|
|
||||||
form.append(key, formField);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
axiosConfig.data = form;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// replace the existing header with a new one that
|
// replace the existing header with a new one that
|
||||||
// contains the boundary property.
|
// contains the boundary property.
|
||||||
|
@ -197,26 +208,7 @@ async function parseRequestObject(requestObject: IDataObject) {
|
||||||
if (requestObject.formData instanceof FormData) {
|
if (requestObject.formData instanceof FormData) {
|
||||||
axiosConfig.data = requestObject.formData;
|
axiosConfig.data = requestObject.formData;
|
||||||
} else {
|
} else {
|
||||||
const objectKeys = Object.keys(requestObject.formData as object);
|
axiosConfig.data = createFormDataObject(requestObject.formData as object);
|
||||||
if (objectKeys.length > 0) {
|
|
||||||
// Should be a standard object. We must convert to formdata
|
|
||||||
const form = new FormData();
|
|
||||||
|
|
||||||
objectKeys.forEach((key) => {
|
|
||||||
const formField = (requestObject.formData as IDataObject)[key] as IDataObject;
|
|
||||||
if (formField.hasOwnProperty('value') && formField.value instanceof Buffer) {
|
|
||||||
let filename;
|
|
||||||
// @ts-ignore
|
|
||||||
if (!!formField.options && formField.options.filename !== undefined) {
|
|
||||||
filename = (formField.options as IDataObject).filename as string;
|
|
||||||
}
|
|
||||||
form.append(key, formField.value, filename);
|
|
||||||
} else {
|
|
||||||
form.append(key, formField);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
axiosConfig.data = form;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Mix in headers as FormData creates the boundary.
|
// Mix in headers as FormData creates the boundary.
|
||||||
const headers = axiosConfig.data.getHeaders();
|
const headers = axiosConfig.data.getHeaders();
|
||||||
|
@ -415,10 +407,26 @@ async function proxyRequestToAxios(
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
// The error-data was made available with request library via "error" but now on
|
Logger.debug('Request proxied to Axios failed', { error });
|
||||||
// axios via "response.data" so copy information over to keep it compatible
|
// Axios hydrates the original error with more data. We extract them.
|
||||||
error.error = error.response.data;
|
// https://github.com/axios/axios/blob/master/lib/core/enhanceError.js
|
||||||
error.statusCode = error.response.status;
|
// Note: `code` is ignored as it's an expected part of the errorData.
|
||||||
|
const { request, response, isAxiosError, toJSON, config, ...errorData } = error;
|
||||||
|
error.cause = errorData;
|
||||||
|
error.error = error.response?.data || errorData;
|
||||||
|
error.statusCode = error.response?.status;
|
||||||
|
error.options = config;
|
||||||
|
|
||||||
|
// Remove not needed data and so also remove circular references
|
||||||
|
error.request = undefined;
|
||||||
|
error.config = undefined;
|
||||||
|
error.options.adapter = undefined;
|
||||||
|
error.options.httpsAgent = undefined;
|
||||||
|
error.options.paramsSerializer = undefined;
|
||||||
|
error.options.transformRequest = undefined;
|
||||||
|
error.options.transformResponse = undefined;
|
||||||
|
error.options.validateStatus = undefined;
|
||||||
|
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue