Search

Why My Ajax Callback Never Fired

This post documents an issue I encountered in a legacy Spring MVC environment using a company-wide common framework
It wasn’t just a bug fix , it led me to finally understand the true behavior of Ajax,
how the browser interprets responses, and how legacy frameworks influence the entire flow.

1. The Problem

“The server is fine, no JavaScript errors… but the Ajax callback never fires.”

The page flow looked like this:
Menu Click → openXXX.do → ModelAndView Controller → JSP render → JavaScript load → document.ready() → Ajax request → callback() updates the table
Plain Text
복사
But the callback was never executed.
Even worse
No JavaScript errors
Server logs clean
HTTP 200 OK
Ajax request appears as “successful” in DevTools
Yet… nothing happens on the screen.
This is one of the most frustrating types of problems in web development.

2. Symptoms (The “Drive-You-Crazy” Type)

Server-side : no exceptions

Browser console : no errors

Network tab : HTTP 200 OK

Ajax request appears normal

But : success/callback NEVER fires

This is the kind of issue that will make any developer lose their mind.
And that’s what happened to me, I spent almost an entire day chasing this.

3. The Key Discovery

When I inspected the Network → Response tab more closely…

The Ajax response was not JSON, but a JSP (HTML).

At that moment, everything clicked.
Ajax was expecting JSON,
but the server responded with HTML —
and that is why the callback never fired.
But why did the server return JSP instead of JSON?
To understand this, we need to clarify one huge misconception.

4. The Big Misconception About Ajax Success

Most developers (including me, until this incident) believe this:
“If the server returns HTTP 200 OK and no errors occurred, Ajax success will run.”
This is wrong.
Very wrong.

5. The Truth : Ajax success Does NOT Mean Server Success

Ajax success = Client-side “response parsing success”

jQuery fires success() only if both of these conditions are met:

(1) HTTP status is 2xx

AND

(2) jQuery successfully parses the response into the type specified by dataType

If JSON was expected, but
server sends HTML
server sends malformed JSON
Content-Type is wrong
response begins with whitespace
session timeout returns login page
JSON parsing fails → jQuery does NOT call success/callback.
This is exactly what happened to me.

6. Why Did the Server Return HTML Instead of JSON?

This was the tricky part.
Our company has strict URL conventions:
Screen entry URLs always use openXXX.do
These URLs must return ModelAndView → JSP
Legacy framework routes them through “screen-loading pipelines”
I didn’t know this and made the rookie mistake:

I registered a data-retrieval Ajax URL using the same pattern as screen-entry URLs.

Example
retrieveSftyInscRsltLst.do
Plain Text
복사
The legacy framework interpreted this URL as a screen-render URL,
and therefore returned HTML instead of JSON.
Ajax expected JSON → received HTML → failed parsing → no callback.
Now the entire issue suddenly made sense.

7. The Solution

Separate “screen entry” and “Ajax retrieval” URLs

Since the screen-entry URL cannot be modified (company-wide standard),
I created a separate retrieval-only URL:
retrieveSftyInscRsltLst2.do
Plain Text
복사

New Ajax controller returning JSON

@RequestMapping("/spc/exmlcarg/simlcsl/retrieveSftyInscRsltLst2.do") public String retrieveList2(..., ModelMap model) { model.addAttribute("totCnt", totCnt); model.addAttribute("resultList", resultList); return "jsonView"; // Ensure JSON response }
Java
복사

Ajax now calls the new URL

$form.kcs4gAjaxFormSubmit({ url : '/spc/exmlcarg/simlcsl/retrieveSftyInscRsltLst2.do', type : 'POST', data : {...}, callback : function(result) { console.log(result); ... } });
JavaScript
복사
Callback started firing immediately. Problem solved.

8. Final End-to-End Flow (Now Cleanly Understood)

[1] User clicks menu → openXXX.do [2] Legacy controller returns ModelAndView [3] JSP rendered [4] JS files loaded [5] document.ready() triggers the first Ajax call [6] Ajax hits retrieveXXX2.do (JSON endpoint) [7] Server returns jsonView [8] jQuery successfully parses JSON → success [9] Legacy common success handler → callback(result) [10] Page table renders normally
Plain Text
복사
This clear separation fixed everything.

9. Bonus : Understanding success vs callback

In our environment:
success = jQuery’s native Ajax success handler
callback = company’s wrapper function that runs after common logic
(session check, resultCode check, global error handling, etc.)
If callback() is not called,
that means success() itself never fired,
which means parsing failed.
This is how I confirmed the issue was on the Ajax → response → parsing side.

10. Key Lessons Learned

1. Ajax success is based on client-side parsing, not server success

Even if the server is 100% correct,
HTML instead of JSON will prevent success() from firing.

2. Legacy frameworks can override URL behavior

URL naming matters more than you think.

3. Always check Network → Response before debugging code

If the response is HTML, XML, or a login page,
Ajax callback will never fire.

4. Separate screen-entry URLs and data-fetch URLs

Especially in enterprise systems:
mixing them will cause unpredictable behavior.

5. A single URL naming mistake can break the entire flow

This mistake cost me almost a full day, but I learned the lesson well.

11. Conclusion

This issue was more than a bug;
it gave me a much deeper understanding of:
Ajax internals
JSON parsing
HTTP request/response behavior
Legacy framework routing
jQuery’s success logic
And the importance of clean URL design
From now on, whenever an Ajax callback doesn’t fire,
I’ll always ask
“Is the response really in the format my Ajax call expects?”
Because 90% of the time, that’s exactly where the problem is.