Keywords: Fetch API | CORS | opaque response
Abstract: This article provides a comprehensive analysis of the root causes behind empty response bodies when using JavaScript Fetch API with no-cors mode. It explains CORS mechanisms, opaque response characteristics, and proper server-side configuration methods. Through detailed code examples, the article demonstrates step-by-step how to correctly configure CORS middleware in Express servers and presents complete implementations of fixed fetch requests.
Problem Phenomenon and Background Analysis
In React/Redux application development, developers frequently encounter situations where response bodies appear empty during cross-origin requests using Fetch API. The specific manifestation is: while the Network tab in Chrome Developer Tools shows successful requests with returned data, accessing response.body or response.text() in JavaScript code returns null or empty strings.
Root Cause: no-cors Mode and Opaque Responses
The core issue lies in the mode: "no-cors" configuration of Fetch API. When this mode is enabled, the browser generates an opaque response. According to the Fetch specification, opaque responses are severely restricted—they do not expose response status, header information, and most importantly, do not provide access to the response body.
This design is based on security considerations. In cross-origin requests, if the target server doesn't explicitly permit access, the browser restricts JavaScript from accessing response content to prevent malicious websites from stealing user data from other sites.
Solution: Proper CORS Configuration
To resolve this issue, both server-side and client-side approaches are necessary:
Server-Side Configuration
For Express servers, install and configure CORS middleware:
npm install corsThen add to server code:
const express = require('express');
const cors = require('cors');
const app = express();
// Enable CORS
app.use(cors());
// Or configure more precisely
app.use(cors({
origin: 'http://your-client-domain.com',
methods: ['GET', 'POST'],
allowedHeaders: ['Content-Type', 'Authorization']
}));Client-Side Code Correction
Remove the mode: "no-cors" configuration and handle responses properly:
fetch('http://example.com/api/node', {
method: 'GET',
headers: {
'Accept': 'application/json'
}
}).then(response => {
if (response.ok) {
return response.json();
}
throw new Error('Network response was not ok.');
}).then(json => {
console.log(json);
// Process retrieved data
return dispatch({
type: 'GET_CALL',
response: json
});
}).catch(error => {
console.log('Request failed', error);
});Deep Understanding of Response Status Checking
In the fixed code, we use response.ok to check response status. This is an important best practice as it covers all 2xx status codes (200-299), ensuring that response body parsing is only attempted when the request is truly successful.
Related Technical Extensions
Referencing discussions around Node.js undici library, when handling empty response bodies, developers can also check response status codes to determine whether response body parsing should be attempted. For example, status code 204 (No Content) explicitly indicates no response body, making it reasonable to skip parsing steps in such cases.
While the undici library provides internal properties like response.body._readableState.length to check for response body presence, production environments should avoid relying on such internal implementations and instead use standard HTTP status codes and CORS mechanisms.
Summary and Best Practices
The key to solving empty response body issues in Fetch API includes:
- Avoid using
no-corsmode when unnecessary - Ensure servers are properly configured with CORS headers
- Use
response.okto check response status - Choose appropriate parsing methods (
.json(),.text(), etc.) based on response content type - Properly handle errors and exceptional cases
By following these best practices, developers can avoid common cross-origin request pitfalls and ensure applications can reliably handle HTTP requests and responses.