A continuation of my blog with a better solution… LOL
Due to my issues with struct handling in the OnCFCRequest method, I thought I’d try a slightly different approach. Basically, I ignored onCFCRequest() and made use of onRequestEnd() instead. It’s similar to the other approach with the added benefit that I don’t have to interrupt the calls and inject my own handler for the content. It can do whatever it was doing before and now I can simply change the Content-Type header in certain circumstances.
Here’s the new method that seems to be doing exactly what I need so far in basic testing.
Application.cfc in OnRequest():
if (ListLast(cgi.script_name, ".") == "cfc") {
contentTypeHandler();
}
And then I added this function in Application.cfc to handle the header conversions. I’m sure it can be optimized, extended, etc but it’s functional right now and that’s the most important thing for me at the moment.
/* @hint Sets headers in certain scenarios to mimic ColdFusion behavior */
private void function contentTypeHandler()
output="false" {
param name="url.fallbackToACF", type="boolean", default=true;
param name="request.fallbackToACF", type="boolean", default=true;
if (!request.fallbackToACF) {
// Using request as priority in case we want to FORCE a specific content-type internally
return;
} else if (!url.fallbackToACF) {
// Otherwise, if the caller wants to adjust the ouput, allow them to do that here
return;
}
// Get cfc name & path in dot-notation formation
var cfcName = cgi.SCRIPT_NAME;
// Drop .cfc from path and change to dots
cfcName = Reverse(ListRest(Reverse(cfcName), "."));
cfcName = listChangeDelims(cfcName, ".", "\/");
// Get method name from url params
var method = "";
for (item in ListToArray(cgi.query_string, "&")) {
var data = ListToArray(item, "=");
if (data.len() == 2) {
if (data[1] == "method") {
method = data[2];
break;
}
}
}
if (!Len(method)) {
// No method discovered so carry on as-is
return;
}
// Doing this in case it wasn't created during app start (ie code added after app started?)
if (!application.keyExists('cfc_cache')) {
application.cfc_cache = {};
}
// Populate cache data for this request if needed
if (!application.cfc_cache.keyExists(cfcName)) {
try {
application.cfc_cache[cfcName] = {
component = createObject("component", cfcName),
meta = {
returnFormat = ""
}
};
} catch (any e) {
// This could happen if the requested template doesn't exist or is just broken for some reason
return;
}
// Now for the part we really need: metadata
application.cfc_cache[cfcName].meta.append(
getMetaData(application.cfc_cache[cfcName].component[method]),
true
);
}
// For now, just modifying json output but might extend or adjuist later as needed
if (application.cfc_cache[cfcName].meta.returnFormat == "json") {
cfheader(name="Content-Type", value="text/html");
}
}
Now I can mimic the (likely incorrect) ColdFusion behavior that sends returnFormat=“json” content back to the call as “text/html”. But I’m also able to override this behavior as needed through either url or request variables (in case I want to force “correct” behavior). Thus far, it’s working splendidly and carry on with my other testing without having to change json or js behaviors to compensate for the difference between Lucee and ColdFusion. So I’m much more optimistic that this may be achievable.