Configure Custom HTTP Parser with Axios in Node.js
This article explains how to configure and use a custom or relaxed
HTTP parser with Axios in Node.js applications. It covers using custom
http.Agent options to bypass strict parsing errors,
processing raw HTTP streams with third-party parsers, and building a
custom Axios adapter for low-level socket parsing.
Method 1: Using Node's Insecure HTTP Parser with Axios
Node.js uses llhttp by default, which enforces strict
HTTP specification compliance. If an API returns non-compliant headers,
Node.js throws errors like HPE_INVALID_HEADER_TOKEN. You
can configure Axios to use Node's relaxed parser via
http.Agent and https.Agent.
const axios = require('axios');
const http = require('http');
const https = require('https');
// Create custom agents with insecureHTTPParser enabled
const httpAgent = new http.Agent({ insecureHTTPParser: true });
const httpsAgent = new https.Agent({ insecureHTTPParser: true });
// Create an Axios instance using the custom agents
const client = axios.create({
httpAgent,
httpsAgent
});
// Make requests with relaxed parsing rules
async function makeRequest() {
try {
const response = await client.get('https://example.com/api/data');
console.log(response.data);
} catch (error) {
console.error('Request failed:', error.message);
}
}
makeRequest();Alternatively, you can enable this globally across the entire Node.js process by launching your script with the CLI flag:
node --insecure-http-parser app.jsMethod 2: Parsing Raw Streams with a Custom HTTP Parser
If you need a completely custom parsing implementation (such as
http-parser-js), configure Axios to return a raw readable
stream and pipe it into your parser.
const axios = require('axios');
const { HTTPParser } = require('http-parser-js');
async function fetchWithCustomParser(url) {
const response = await axios.get(url, {
responseType: 'stream'
});
const parser = new HTTPParser(HTTPParser.RESPONSE);
parser[HTTPParser.kOnHeadersComplete] = (info) => {
console.log('Parsed Headers:', info.headers);
};
parser[HTTPParser.kOnBody] = (chunk, offset, length) => {
const bodyChunk = chunk.slice(offset, offset + length).toString();
console.log('Parsed Body Chunk:', bodyChunk);
};
parser[HTTPParser.kOnMessageComplete] = () => {
console.log('Parsing complete.');
};
response.data.on('data', (chunk) => {
parser.execute(chunk, 0, chunk.length);
});
response.data.on('end', () => {
parser.finish();
});
}
fetchWithCustomParser('https://jsonplaceholder.typicode.com/todos/1');Method 3: Implementing a Custom Axios Adapter
For full control over network sockets and response parsing, you can implement a custom Axios adapter.
const axios = require('axios');
const net = require('net');
const tls = require('tls');
const url = require('url');
const customParserAdapter = (config) => {
return new Promise((resolve, reject) => {
const parsedUrl = url.parse(config.url);
const isHttps = parsedUrl.protocol === 'https:';
const port = parsedUrl.port || (isHttps ? 443 : 80);
const host = parsedUrl.hostname;
const transport = isHttps ? tls : net;
const socket = transport.connect(port, host, () => {
// Build raw HTTP request
const requestData = `${config.method.toUpperCase()} ${parsedUrl.path || '/'} HTTP/1.1\r\n` +
`Host: ${host}\r\n` +
`Connection: close\r\n\r\n`;
socket.write(requestData);
});
let rawData = '';
socket.on('data', (chunk) => {
rawData += chunk.toString();
});
socket.on('end', () => {
// Apply custom parsing logic to the raw socket output
const [headerBlock, ...bodyParts] = rawData.split('\r\n\r\n');
const body = bodyParts.join('\r\n\r\n');
const response = {
data: body,
status: 200,
statusText: 'OK',
headers: { rawHeaders: headerBlock },
config,
request: socket
};
resolve(response);
});
socket.on('error', (err) => {
reject(err);
});
});
};
// Use the custom adapter with Axios
const customClient = axios.create({
adapter: customParserAdapter
});
customClient.get('https://example.com')
.then(res => console.log('Response via custom adapter:', res.data))
.catch(err => console.error(err));