Keywords: CORS | preflight request | redirect error
Abstract: This article delves into the common 'preflight is invalid (redirect)' error in CORS preflight requests, explaining that the root cause lies in servers returning 3xx redirect responses instead of 2xx success responses to OPTIONS requests. It details the conditions that trigger CORS preflight, including non-simple request methods, custom headers, and non-standard Content-Types. Through practical examples, the article offers multiple solutions: checking and correcting trailing slash issues in URLs, avoiding preflight triggers, using redirected URLs directly, and properly handling responses in proxy scenarios. Additionally, it discusses supplementary causes like HTTPS-HTTP protocol mismatches and provides specific steps for debugging using browser developer tools.
Core Mechanism of CORS Preflight Requests and Redirect Errors
In the context of Cross-Origin Resource Sharing (CORS), when a browser detects that a request does not meet simple request criteria, it first sends a preflight OPTIONS request to the server to confirm if the actual request is safe. According to the W3C specification, the preflight request must receive a successful response with a 2xx status code for the browser to proceed with the actual request. If the server returns a 3xx redirect response to the OPTIONS request, the browser throws the "preflight is invalid (redirect)" error, as redirects are not allowed for preflight requests. This is often caused by server configuration or request URL issues.
Analysis of Conditions Triggering Preflight Requests
Browsers send preflight requests under the following conditions: the request method is not GET, HEAD, or POST; custom request headers are set, such as Authorization or X-Custom-Header, which are not in the simple request header list (including Accept, Accept-Language, Content-Language, Content-Type, etc.); or the Content-Type value is not application/x-www-form-urlencoded, multipart/form-data, or text/plain. For example, using application/json as Content-Type triggers preflight. Understanding these conditions helps developers adjust code to avoid unnecessary preflight requests.
Common Solution: Trailing Slash Issues in URLs
The most frequent cause of the error is missing or extra trailing slashes in URLs. For instance, if the request URL is https://example.com/api/resource but the server expects https://example.com/api/resource/, the server may return a 301 redirect to the version with a slash, causing preflight failure. The solution is to check the browser developer tools' network panel, examine the Location header in the response to the OPTIONS request to get the redirected URL, and use that URL directly in code. Here is an example code snippet demonstrating how to correct the URL:
// Incorrect example: missing trailing slash
const url = 'https://serveraddress/api/auth/login';
// Corrected: add trailing slash
const correctedUrl = 'https://serveraddress/api/auth/login/';
// Send request using fetch API
fetch(correctedUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ key: 'value' })
}).then(response => response.json()).then(data => console.log(data));This approach avoids server redirects, ensuring the preflight request succeeds.
Advanced Scenario: Proxy Servers and Third-Party Endpoints
In some cases, developers may use proxy servers to handle CORS requests, e.g., frontend code sends requests to their own proxy, which forwards to a third-party API. If the proxy simply redirects the OPTIONS request to the third-party endpoint, the browser receives a response from a different origin, causing preflight failure. The correct approach is for the proxy server to receive the response from the third-party endpoint, process it, and then return its own response to the frontend. This ensures the preflight response origin matches the request origin. For example, in Node.js, Express middleware can be used:
const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
app.options('/proxy', (req, res) => {
// Handle preflight request, return 2xx response
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.sendStatus(200);
});
app.post('/proxy', async (req, res) => {
try {
const response = await axios.post('https://third-party.com/api', req.body);
res.json(response.data);
} catch (error) {
res.status(500).send('Proxy error');
}
});
app.listen(3000, () => console.log('Proxy server running on port 3000'));Thus, the frontend sends requests to http://localhost:3000/proxy, and the proxy handles preflight and actual requests, avoiding redirect issues.
Supplementary Causes and Debugging Techniques
Beyond trailing slashes, other causes may lead to this error. For example, if a request uses HTTP protocol but the server requires HTTPS, the server may redirect to the HTTPS version, triggering preflight failure. Ensuring correct URL protocols is key. Use browser developer tools for debugging: open the network panel, filter for OPTIONS requests, and inspect response status codes and headers. If a 3xx status code is seen, check the Location header to identify the redirect target. Additionally, verify server CORS configuration is correct, ensuring headers like Access-Control-Allow-Origin are properly set. For ASP.NET Web API, when enabling CORS per Microsoft documentation, be cautious of middleware conflicts that may cause redirects.
Conclusion and Best Practices
Resolving the "preflight is invalid (redirect)" error requires a systematic approach: first, identify if preflight is triggered and avoid it by adjusting request methods or headers; second, check URL format, correcting trailing slashes or protocol issues; in proxy scenarios, ensure the proxy properly handles responses rather than simply redirecting. Developers should prioritize simple requests to reduce preflight overhead and implement server-side solutions in complex cases. By combining theoretical analysis with practical code, the reliability and performance of cross-origin requests can be significantly enhanced.