Copy link to clipboard
Copied
Well, this is an extremely frustrating function. Especially for produces="application/json"
Depending on what you set the status to, your content is overridden by messages or default templates.
A few test functions:
status 401, 404 return body with html default template instead of specified content
//test function for 404 - returns html default template
remote void function notfound()
httpmethod="GET"
restpath="/not-found"
{
response = {
content: "Oops, not found",
status: 404
};
restSetResponse(response);
}
status 422 returns body with html "The custom error module does not recognize this error."
//test function for 422 - returns "The custom error module does not recognize this error."
remote void function UnprocessableEntity()
httpmethod="GET"
restpath="/unprocessable-entity"
{
response = {
content: "Oops, unprocessable entity",
status: 422
};
restSetResponse(response);
}
The purpose of having produces="application/json" was to always have the body/content a JSON structure -
which obviously isn't going to happen if my content is ignored. For example -
//json structure for errors
private Struct function handlerError( required string funcName, required any e)
{
var funcResp = structNew();
funcResp.error = true;
funcResp.msg = ARGUMENTS.e.message;
funcResp.type = ARGUMENTS.funcName & " -> " & ARGUMENTS.e.type;
funcResp.error_code = ARGUMENTS.e.errorCode;
return SerializedJSON(funcResp);
}
// should return for 422
{"error":true,"msg":"Oops, unprocessable entity","type":"Unprocessible Entity","error_code":"422"}
// should return for 404
{"error":true,"msg":"Oops, not found","type":"Not Found","error_code":"404"}
How can I override the override, so my content is returned in the body?
Environment: Windows Server 2012R2 v6.2, CF2016, IIS v8
When you serialize to JSON you essentially get a string. But, here, your function is returning a struct instead.
So, you should modify the code to something like
private String function handlerError( required string funcName, required any e)
{
var funcResp = structNew();
funcResp.error = true;
funcResp.msg = ARGUMENTS.e.message;
funcResp.type = ARGUMENTS.funcName & " -> " & ARGUMENTS.e.type;
funcResp.error_code = ARGUMENTS.e.errorCode;
re...
Copy link to clipboard
Copied
When you serialize to JSON you essentially get a string. But, here, your function is returning a struct instead.
So, you should modify the code to something like
private String function handlerError( required string funcName, required any e)
{
var funcResp = structNew();
funcResp.error = true;
funcResp.msg = ARGUMENTS.e.message;
funcResp.type = ARGUMENTS.funcName & " -> " & ARGUMENTS.e.type;
funcResp.error_code = ARGUMENTS.e.errorCode;
return serializeJson(funcResp);
}
Copy link to clipboard
Copied
Thank you for pointing out what should have been staring me in the face!
Copy link to clipboard
Copied
Hello,
This seems relevant as I'm trying to add some AJAX to an existing application, but I ran into the same general issue.
Can I have the same JSON handling when output is done with the following approach?
getPageContext().getResponse().setStatus(422);
getPageContext().getResponse().setContentType('application/json; charset=utf-8');
writeOutput(serializeJson(data));
Copy link to clipboard
Copied
Sergii, I appreciate you're likely hoping to hear from anyone who "knows the answer" to your challenge. Maybe someone will, but until then perhaps the following will help us help you.
1) Have you tried simply using cfheader and cfcontent instead? I ask because by dropping to the lower level of Tomcat (the servlet context, via that cfml getpagecontext function), you may be getting or losing something as compared to the purely cfml approach. It's worth a try--and it requires no mods to cf or iis or your application.cfc (more on that in a moment)
2) Also, is this code being done in a method of a cfc? If so, what's the method's returntype and returnformat? Are you setting one or leaving it as the default? And is this cfc being called directly via http? That has its own impact on how content is returned.
3) You've also not clarified what web server you're using. You mentioned iis. That could be configured in a way that's impacting thus behavior, especially non-200 status codes.
It could be interesting to hear if the result would be different if you called such a page via cf's builtin web server, which is how folks access the cf admin, by default at port 8500 (to run code in the cfusion/wwwroot folder).
4) to that last point, have you tried things in other than the one environment you're referring to? Do you have a test environment? A free development environment? Even if that wouldn't work for your entire app, at least you could test small samples which would help you know where the issue may be, if it happens one place or way but not another.
5) It may help us to know what Cf version you're running.
6) Finally, back to the discussion of application.cfc, why is it off-limits for you to modify that? Is it that you don't want to affect other templates in that same folder or its subfolders? Couldn't you put this sort of code in its own folder with its own application.cfc? that could even be coded to leverage things in the parent's app? The reason that "can't work" for you may well be clear to you and would make sense if you relayed it, but I wanted to ask. Again, it may not even be necessary for this challenge.
Hope that's helpful.
Copy link to clipboard
Copied
Thank you for your prompt answer Charlie!
It's hard to structure by thse points exactly, but I'll try:
1) Yes, no luck. Tried by rebuilding from the inside and just by making a super bare-bones sample with just cfheader and cfcontent - all the same.
2) CFC, but it's called indirectly. I structured my part of the application similar to a typical fw/1 app, except that I don't have Application.cfc or the framework itself, but some of it's functions (including shortcutting to JSON output skipping a layout) are replicated by other CFCs.
3) It's mostly stock CF and stock stub pages identical to what Martie has originally reported on this topic.
4) Sure, I tried on Lucee local env and it doesn't have any issues whatsoever.
5) It's CF2021 on the target environment
6) Business reasons. They don't want relative outsiders crash anything outside of the job scope. I agree, that would have put a lot of additional strain on their QA.
If I could have my own Application.cfc etc, I'd just drop in a framework that handles all of it, but currently I can't. My goal is to modernize it from the inside without touching any of the older parts.
Hope it explains it. I know that it's weird.
Copy link to clipboard
Copied
Sergii, on your reply to my point 4, I didn't ask about Lucee at all. I was referring to the free Adobe cf dev edition. You should setup both, so you can test against both, sure. But you need cf to test against since that's what you're running on the server. Again we need to find WHERE the problem is happening.
Indeed, as for your answer to my point 3, I don't see how what you say relates to what I'd asked. Your call if you want to clarify, but it goes to that last point.
Finally in saying you feel that in replying to me "It's hard to structure by thse points exactly", feel free to reply otherwise. I numbered them hoping to make it easy. Sorry if somehow it didn't help.
Copy link to clipboard
Copied
@Sergii Melnykov , you should perhaps start a new thread of your own. I say this because it seems your context is different from that of this thread. Your context involves a call to a CFC. Whereas the context of this thread is a request to a REST API, hence the use of
// The responseStruct has keys such as status, content and headers
RESTSetResponse(responseStruct);
Copy link to clipboard
Copied
While there may well be a benefit to sergii creating a new thread, it shouldn't be for the reason you state. The RestSetResponse method is in fact part of the cf rest services feature added in cf 10.
So Sergii, you replied to me saying that you were indeed using a cfc that's called "indirectly". Are you in fact calling it as registered through cf's rest support? If not, that could be another reason that what you're using may not be working as expected. Let us know more.
Copy link to clipboard
Copied
Thanks for taking care!
Well, okay, so I have an antry point .cfm that invokes "framework" .cfcs like DI/IoC/service cache handler and global variables (like request context) init&management. And they take care of resolving all the MVC routing. And one of the aspects is cutting right to the output without any templating. So, index.cfm invokes a .cfc right next to it and that .cfc has a method that does what I've posted above (not really, but I compressed it to these 3 lines).
And I'm not sure what's wrong with my case, because I've seen very similar implementations. The only thing that I can't do is have an onError() for the Application.cfc, but knowing ColdFusion and that there are always 4 different ways to do the same thing, I decided to try and ask around - especially when I saw it resolved for a case that looks exactly like mine on the outside (although differs within by exposing the service directly).
Copy link to clipboard
Copied
While there may well be a benefit to sergii creating a new thread, it shouldn't be for the reason you state. The RestSetResponse method is in fact part of the cf rest services feature added in cf 10.
By @Charlie Arehart
I really don't understand what you mean. I think you don't understand what I meant either. So, let me repeat my reason.
This thread is originally about RESTSetResponse. Sergii's question is about a call to a CFC. ColdFusion handles a REST response differently from how it handles a response to a CFC, hence my suggestion to start a new thread.
Copy link to clipboard
Copied
Thanks for the advice!
It does look different on the inside, I just caught a glimpse of the same situation on the outside: i.e. serialized JSON as on output and a proper status&content type being replaced by a generic error handler stub. This is as close as I could get through my search. I might give it a try next day, but honestly with this level of immediate feedback it's unlikely for me to get any better answers than that.
Copy link to clipboard
Copied
@Sergii Melnykov ,. I think the code is correct. In any case, I can see nothing wrong with it.
However, I have a question. Why the status-code 422?
Copy link to clipboard
Copied
Hmm, my previous answer seems to be lost.
So 422 is just an example as QA wanted to the whole range of typical status codes supported, from 400 to 422 (situation vary: missing attributes, wrong attribute ranges, wrong methods, missing endpoints, session time out, missing access rights for the entity, some processed DB failures). In my case it doesn't really matter as all of them got intercepted and only the body differs: 400 might be just a plain text status description and 404/405 are full html pages.
Copy link to clipboard
Copied
Since you're not using the cf rest framework, I'd say the behavior to expect from that Cf function is undefined. But then you said earlier that your attempt to use cfheader and cfcontent didn't work. It seems like something is potentially interfering.
So I'll go back to my earlier point that you never addressed: create a local cf development environment and try things there. And in your bare bones example, put it in a folder with an empty application.cfc, to keep any code in another or the parent folders from causing unexpected impact.
And test it both with the cf builtin web server, and with whatever real web server you use (iis?), to see if those differ. I don't think this is an insurmountable problem: it's just a challenging one and we're giving you ideas to pursue. (and I'm always writing from a phone when I see these, so I'm not testing things myself. Perhaps bkbk will.)
Copy link to clipboard
Copied
Thank you!
I wanted to add to my previous answers and clarify:
On a pristine local setup of CF2021 with just the built-in Tomcat & a distilled cased of a pure .cfm with just cfheader and cfcontent I seem to be able to return the desired result of a clear JSON with a 4xx code I do get a desired result.
On a test server with CF2021 & IIS (and probably non-standard CFAdmin settings) I get substitutes for any 4xx responses. Can't say it's unusual (had a plenty of them back ~10 years ago), but I just can't figure what's causing the override exactly. Is it just IIS taking authority? Or app server can sort of "not report them as errors" to web server - and I'm just missing the exact trigger?
Copy link to clipboard
Copied
There you go. That's why I pressed with all the questions.
Yes, what you show is a. Iis-generated page. If cf returns a 405, for example, then iis shows that page you shared.
And that's controlled by the iis "error pages" feature, configurable at either the site or server level of iis. You would have a couple options.
You could use its "edit feature settings" feature, and change it to show detailed errors to local and remote users.
Or you could delete each of the listed "custom error page" links such as that for 405 and so on.
Let us know how it goes.
Copy link to clipboard
Copied
Oh sure and I appreciate that!
However for now IIS configuration is out of the question (just like anything else outside of the module I'm working on) and hence the case here seemed to have an identical problem (and supposedly has been resolved from within CF!) I gave it a try anyway.
Copy link to clipboard
Copied
Alright, @BKBK @Charlie Arehart I owe you a solution.
So, what seems to have solved the issue is the following sequence:
1) go to IIS, find the application, open the Error Pages widget
2) click Edit Feature Settings and select Detailed Errors
3) for status codes you need to support, choose or add the to the list, but change path to a custom script, it could be something akin to /views/errors/<code>.cfm within your application, content could be as sophisticated as needed (perhaps, some logging) or just a copy of a static system 404/405 page.
...and that's it, solves the problem, my JSON content is passed and headers are not changed.
There were alternative options I was willing to try, but since this one worked and customers agreed on that until they find a better option, I consider it a temporary, but a solution none the less.
Copy link to clipboard
Copied
@Sergii Melnykov , thanks for sharing your findings.
Get ready! An upgraded Adobe Community experience is coming in January.
Learn more