Fix: Allow empty Content-Type when no body (#1693)

By default Axios will set the Content-Type for POST/PUT/PATCH requests
to "application/x-www-form-urlencoded" if the Content-Type header is not
specified.

This explicitly sets the content type to "false" when there the body
mode is set to "none", and the user has not set an explicit content type
themselves. Setting the content type to false directs Axios not to send
a Content-Type header.
This commit is contained in:
betawait
2025-02-09 21:13:30 +09:00
parent 942c0ee113
commit 1d12bebce4
4 changed files with 71 additions and 35 deletions

View File

@@ -69,45 +69,47 @@ const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, proc
const contentType = getContentType(request.headers);
/*
We explicitly avoid interpolating buffer values because the file content is read as a buffer object in raw body mode.
Even if the selected file's content type is JSON, this prevents the buffer object from being interpolated.
*/
if (contentType.includes('json') && !Buffer.isBuffer(request.data)) {
if (typeof request.data === 'string') {
if (request.data.length) {
request.data = _interpolate(request.data, {
if (typeof contentType === 'string') {
/*
We explicitly avoid interpolating buffer values because the file content is read as a buffer object in raw body mode.
Even if the selected file's content type is JSON, this prevents the buffer object from being interpolated.
*/
if (contentType.includes('json') && !Buffer.isBuffer(request.data)) {
if (typeof request.data === 'string') {
if (request.data.length) {
request.data = _interpolate(request.data, {
escapeJSONStrings: true
});
}
} else if (typeof request.data === 'object') {
try {
const jsonDoc = JSON.stringify(request.data);
const parsed = _interpolate(jsonDoc, {
escapeJSONStrings: true
});
request.data = JSON.parse(parsed);
} catch (err) {}
}
} else if (typeof request.data === 'object') {
try {
const jsonDoc = JSON.stringify(request.data);
const parsed = _interpolate(jsonDoc, {
escapeJSONStrings: true
});
request.data = JSON.parse(parsed);
} catch (err) {}
} else if (contentType === 'application/x-www-form-urlencoded') {
if (typeof request.data === 'object') {
try {
forOwn(request?.data, (value, key) => {
request.data[key] = _interpolate(value);
});
} catch (err) {}
}
} else if (contentType === 'multipart/form-data') {
if (Array.isArray(request?.data) && !(request.data instanceof FormData)) {
try {
request.data = request?.data?.map(d => ({
...d,
value: _interpolate(d?.value)
}));
} catch (err) {}
}
} else {
request.data = _interpolate(request.data);
}
} else if (contentType === 'application/x-www-form-urlencoded') {
if (typeof request.data === 'object') {
try {
forOwn(request?.data, (value, key) => {
request.data[key] = _interpolate(value);
});
} catch (err) {}
}
} else if (contentType === 'multipart/form-data') {
if (Array.isArray(request?.data) && !(request.data instanceof FormData)) {
try {
request.data = request?.data?.map(d => ({
...d,
value: _interpolate(d?.value)
}));
} catch (err) {}
}
} else {
request.data = _interpolate(request.data);
}
each(request.pathParams, (param) => {

View File

@@ -392,6 +392,13 @@ const prepareRequest = async (item, collection = {}, abortController) => {
axiosRequest.data = graphqlQuery;
}
// if the mode is 'none' then set the content-type header to false. #1693
if (request.body.mode === 'none') {
if(!contentTypeDefined) {
axiosRequest.headers['content-type'] = false;
}
}
if (request.script) {
axiosRequest.script = request.script;
}

View File

@@ -100,4 +100,13 @@ describe('interpolate-vars: interpolateVars', () => {
});
});
});
describe('Handles content-type header set to false', () => {
it('Should result empty data', async () => {
const request = { method: 'POST', url: 'test', data: undefined, headers: { 'content-type': false } };
const result = interpolateVars(request, { 'test.url': 'test.com' }, null, null);
expect(result.data).toEqual(undefined);
});
});
});

View File

@@ -59,4 +59,22 @@ describe('prepare-request: prepareRequest', () => {
expect(result).toEqual(expected);
});
});
describe.each(['POST', 'PUT', 'PATCH'])('POST request with no body', (method) => {
it('Should set content-type header to false if method is ' + method + ' and there is no data in the body', async () => {
const request = { method: method, url: 'test-domain', body: { mode: 'none' } };
const result = await prepareRequest({ request, collection: { pathname: '' } });
expect(result.headers['content-type']).toEqual(false);
});
it('Should respect the content-type header if explicitly set', async () => {
const request = {
method: method,
url: 'test-domain',
body: { mode: 'none' },
headers: [{ name: 'content-type', value: 'application/json', enabled: true }]
};
const result = await prepareRequest({ request, collection: { pathname: '' } });
expect(result.headers['content-type']).toEqual('application/json');
});
});
});