Describe the bug
- Node.js version: not executed locally; static check used Got
v15.0.7, which declares Node.js >=22
- OS & version: not OS-specific
Got's documentation describes prefixUrl as "prepended to url", and the quick start says paths must be relative to the prefix. The options documentation also notes that absolute URLs require prefixUrl: ''.
That explains why an absolute string URL is not prefixed. The surprising part is that when an extended instance has both prefixUrl and default headers, calling the instance with an absolute string URL skips the prefix but still sends the inherited headers to that absolute URL.
That makes an extended instance behave less like an origin-specific API client than the prefixUrl examples suggest.
Actual behavior
Given an instance like this:
const client = got.extend({
prefixUrl: 'http://127.0.0.1:3000',
headers: {
authorization: 'Bearer demo-token',
},
});
A relative path is sent to the prefixed API origin:
Calling the same instance with an absolute string URL:
await client('http://127.0.0.1:4000/collect');
sends the request to 127.0.0.1:4000, and the inherited authorization header is still present on that request.
Expected behavior
For an instance configured with both prefixUrl and default headers, I would expect inherited origin-specific headers not to be sent when the request URL is an absolute URL with a different origin from prefixUrl.
If the current behavior is intended, it would help to document explicitly that absolute string URLs skip prefixUrl while still inheriting instance headers/options.
Code to reproduce
import http from 'node:http';
import got from 'got';
const listen = async server => new Promise(resolve => {
server.listen(0, '127.0.0.1', () => {
const {port} = server.address();
resolve(`http://127.0.0.1:${port}`);
});
});
const apiServer = http.createServer((_request, response) => {
response.end('api server');
});
const otherServer = http.createServer((request, response) => {
console.log('received by other origin:', {
url: request.url,
authorization: request.headers.authorization,
});
response.end('other server');
});
const apiUrl = await listen(apiServer);
const otherUrl = await listen(otherServer);
const client = got.extend({
prefixUrl: apiUrl,
headers: {
authorization: 'Bearer demo-token',
},
});
await client('collect');
await client(`${otherUrl}/collect`);
apiServer.close();
otherServer.close();
Observed output:
received by other origin: {
url: '/collect',
authorization: 'Bearer demo-token'
}
Checklist
Static version check: the current GitHub tag line ends at v15.0.7, and the checked source is 66ca4e025622e1dd71f4e4f13aa6e1b79d61b069 (v15.0.7). The same behavior was previously observed on v15.0.6; I can provide more environment details if useful.
Describe the bug
v15.0.7, which declares Node.js>=22Got's documentation describes
prefixUrlas "prepended tourl", and the quick start says paths must be relative to the prefix. The options documentation also notes that absolute URLs requireprefixUrl: ''.That explains why an absolute string URL is not prefixed. The surprising part is that when an extended instance has both
prefixUrland default headers, calling the instance with an absolute string URL skips the prefix but still sends the inherited headers to that absolute URL.That makes an extended instance behave less like an origin-specific API client than the
prefixUrlexamples suggest.Actual behavior
Given an instance like this:
A relative path is sent to the prefixed API origin:
Calling the same instance with an absolute string URL:
sends the request to
127.0.0.1:4000, and the inheritedauthorizationheader is still present on that request.Expected behavior
For an instance configured with both
prefixUrland default headers, I would expect inherited origin-specific headers not to be sent when the request URL is an absolute URL with a different origin fromprefixUrl.If the current behavior is intended, it would help to document explicitly that absolute string URLs skip
prefixUrlwhile still inheriting instance headers/options.Code to reproduce
Observed output:
Checklist
Static version check: the current GitHub tag line ends at
v15.0.7, and the checked source is66ca4e025622e1dd71f4e4f13aa6e1b79d61b069(v15.0.7). The same behavior was previously observed onv15.0.6; I can provide more environment details if useful.