Hi! I recently started a project that needs to send POST requests to a legacy API on another domain (I don’t manage the API and can’t modify it). For this reason, Netlify’s rewrite rules (i.e. a redirect rule with status code 200) was the perfect feature to integrate it since I need to avoid CORS. The API needs to receive a Content-Type: text/xml; charset=utf-8
header. Since I’m configuring fetch
in no-cors
mode, I cannot set this header directly (it’s restricted, see Using the Fetch API - Web APIs | MDN for the allowed headers). Thus, I created the following redirect rule in my netlify.toml
file:
[[redirects]]
from = "[source-url]"
to = "[legacy-api]"
status = 200
force = true
[redirects.headers]
Content-Type = "text/xml; charset=utf-8"
Accept-Language = "unimportant"
SOAPAction = "unimportant"
The JS code I’m running to send the request is:
const config: RequestInit = {
method: 'POST',
mode: 'no-cors',
body: '[unimportant XML string]'
};
fetch('[source-url]', config);
Now, the fetch
client will add a Content-Type: application/x-www-form-urlencoded
header since I specified a string as the body
parameter.
The API sends a 400 Bad Request response, and rightly so. I changed the [legacy-api]
URL to a local URL so I could dump the raw request. Here’s what I got (some headers were hidden for privacy):
--> POST / HTTP/1.1
--> Host: XXX.localhost.run
--> X_Forwarded_For: XXX
--> X_Forwarded_Proto: https
--> X_Forwarded_Host: XXX
--> User-Agent: curl/X.X.X
--> Content-Length: 457
--> Accept: */*
--> Accept-Language: es-es
--> Client-Ip: XXX
--> Content-Type: application/x-www-form-urlencoded
--> Content-Type: text/xml; charset=utf-8
--> Forwarded: for=XXX;proto=https
[etc.]
--> Accept-Encoding: gzip
-->
--> [unimportant XML string]
-->
As you can see, the Netlify server sent a duplicated header. This is undefined behavior per RFC 7230 (Section 3.2.2):
A sender MUST NOT generate multiple header fields with the same field name in a message unless either the entire field value for that header field is defined as a comma-separated list [i.e., #(values)] or the header field is a well-known exception (as noted below).
I would expect the proxy to override the Content-Type
header sent by the client (which I cannot change, since fetch
sets it by default, and is a restricted header in no-cors
mode). The other valid solution (but, imo less useful) is to send the client’s header. However, they cannot be sent at the same time.
My site name is https://crtm-card-status.netlify.app/; the real API route is /status
, and I’m using /netdebug
with the same headers for testing.
Thanks in advance!