"Whose fault is this bug—frontend or backend?"—The art of passing the buck
Who Touched My API?
The most classic scenario in a development team is: the page displays abnormally, the tester throws out a screenshot, the product manager frowns, while the frontend and backend developers silently open their respective code editors. Suddenly, the air goes quiet, and everyone is waiting for an answer—who’s to blame this time?
The Basic Troubleshooting Trio
Before pointing fingers, these basic steps can quickly narrow down the issue:
- Browser Developer Tools: Press F12 and head straight to the Network tab to check if the API response matches expectations. If the response data itself is wrong, the backend is likely at fault.
// Frontend's expected user data structure
const expected = {
id: 123,
name: '张三',
avatar: 'https://example.com/1.jpg'
}
// Actual response (missing avatar field)
const actual = {
id: 123,
name: '张三'
}
-
API Documentation Check: Compare with Swagger or YAPI documentation to spot issues like mismatched field types or missing required fields.
-
CURL Command Verification: Bypass the frontend and test the API directly via command line:
curl -X GET 'https://api.example.com/user/123'
Classic Frontend Blame Scenarios
When these situations occur, the blame likely falls on the frontend developer:
Data Rendering Issues:
// Lack of null checks causing page crashes
function UserProfile({ user }) {
return <div>{user.detail.address.street}</div>
// GG when address is null
}
Incorrect Parameter Format:
// Backend expects a string number, but frontend sends a Number type
fetch('/api/delete', {
method: 'POST',
body: JSON.stringify({ id: 123 }) // Should be "123"
})
Cache Problems:
// Use random parameters to bypass browser cache
fetch(`/api/data?t=${Date.now()}`)
Classic Backend Problem Scenes
These scenarios justify calling out the backend developer:
500 Errors: A glaring red 500 status code in the Network tab, especially with a long stack trace.
Data Logic Errors:
// Frontend requests pageSize=10, but the API returns 15 items
fetch('/api/list?page=1&pageSize=10')
CORS Issues:
When CORS errors appear in the browser console, it’s usually because the backend didn’t configure Access-Control-Allow-Origin
.
The Gray Release Mystery
Sometimes the issue lies in the release process itself:
- Frontend deploys a new version, but the backend API isn’t ready yet.
- Backend updates the API, but the frontend is still using an old cache.
- A service node failed to deploy the new code.
In such cases, check:
# Check frontend version
document.querySelector('meta[name="version"]').content
# Confirm API version
curl -I https://api.example.com | grep X-Api-Version
Advanced Investigation Techniques
Logging and Analytics:
// Add logs to critical operations
console.log('API request params:', params)
console.log('DOM state:', document.getElementById('app').innerHTML)
Mock Data Validation:
// Use local JSON files to bypass real APIs
beforeEach(() => {
jest.mock('./api', () => ({
getUser: () => Promise.resolve(require('./mock/user.json'))
}))
})
Time-Travel Debugging: Use Redux DevTools to replay state changes and pinpoint when things went wrong.
When Things Get Complicated
Some issues require joint debugging:
- Data Inconsistency: Frontend shows "1 item left," but the order fails due to being sold out.
- Permission Issues: Admin can see a button but gets a 403 error when clicking.
- File Upload Failures: Frontend shows success, but the backend didn’t receive the file.
Here’s what to do:
- Compare the FormData sent by the frontend with what the backend received.
- Check if the
Content-Type
header is correct. - Review request logs in Nginx or other middleware.
Automated Defense Strategies
Prevention is better than blame:
Frontend Defensive Programming:
interface User {
id: string
name: string
avatar?: string
}
function renderAvatar(user: User) {
return user.avatar
? <img src={user.avatar} />
: <DefaultAvatar />
}
Backend Contract Testing:
// Spring Boot test example
@WebMvcTest
public class UserApiTest {
@Test
void shouldReturnUserWithAvatar() throws Exception {
mockMvc.perform(get("/user/1"))
.andExpect(jsonPath("$.avatar").exists());
}
}
Monitoring and Alerts:
- Frontend error tracking (Sentry)
- API success rate alerts (Prometheus)
- Log aggregation (ELK)
Blame Stories from the Trenches
Real-world examples:
- Cache Avalanche: Frontend says the API is slow, backend says queries are fast—turns out the Redis cluster crashed.
- Timezone Mystery: Frontend shows dates one day earlier—backend forgot to convert to UTC.
- Encoding Issues: User inputs emoji, frontend sends UTF-8, backend receives GBK.
- CDN Blame: Stylesheets didn’t update—CDN cache settings were misconfigured.
- Nginx Shenanigans: API returns 403—turns out
client_max_body_size
was too small.
The Ultimate Peace Treaty
When all else fails:
- Joint Debugging Session: Frontend, backend, and QA walk through the flow together.
- Code Swap: Frontend writes a mock backend API; backend writes a mock frontend page.
- Traffic Replay: Use tools like Charles to record and replay production requests.
- End-to-End Logging: Trace a request’s full lifecycle with a TraceID.
// Add a TraceID to requests
const traceId = Math.random().toString(36).substr(2)
fetch('/api/data', {
headers: { 'X-Trace-Id': traceId }
})
From Blame to Responsibility
The path to becoming a better developer:
- Assume it’s your fault first—investigate before pointing fingers.
- Include full context when reporting bugs (environment, steps, logs).
- Solve problems with code, not arguments.
- Write post-mortems for critical issues.
- A round of bubble tea resolves 90% of blame conflicts.
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn