Does anyone have any good CORS info as it relates ...
# fw1
b
Does anyone have any good CORS info as it relates to FW1? I'm running in to so weird issues and I think I'm setting up the preflight options and such correctly in the framework settings. It works great on my dev but when I take it to production, all hell breaks loose and I can't get JSON back from my app.
s
Can you show us how you have it set up and what exactly the browser devtools shows when you try to run it on production?
It should "just work" if you have it setup correctly...
b
Here is my framework config:
Copy code
variables.framework = {
		diLocations: [
			"/services",
			"/controllers"
		],
		reloadApplicationOnEveryRequest: true,
		generateSES: true,
		optionsAccessControl: {
			headers: "Content-Type,sentry-trace",
			origin: getAccessControlOrigin()
		},
		preflightOptions: true,
		routes: getRoutes(),
		sesOmitIndex: true,
		trace: false
	};
getAccessControlOrigin()
is a method that returns a different host based on the environment. I can confirm it's returning the expected value in both production and development, so I don't think that's the issue
Here's the route that I'm trying to hit:
Copy code
{
				"/api/organizations": "/api:organizations/default"
			},
The preflight response checks out. However, the response to get the data comes back with
Content-Type: text/html;charset=UTF-8
even though I'm using the
renderData()
method and providing a type of "json". I know that's set up correctly because if I hit the URL directly, it returns the right header and data.
What I find a bit odd is that even though I pass
.header( "Access-Control-Allow-Origin", origin )
to
renderData()
, the header isn't set. I can set it with .htaccess, but that seems beside the point.
This is the relevant code that is executed based on the route defined above:
Copy code
public function default(
	required struct rc
) {
	return framework.renderData()
		.type( "json" )
		.header( "Access-Control-Allow-Origin", getAccessControlOrigin() )
		.data( request.settings.organizations );
}
m
2 thoughts - we added a
cfheader( name="Vary", value="Origin" );
because of some strange CORs issues we were encountering (though I don't remember the specifics)
and I usually add an explicit
return;
following
renderData()
, unless
after
is being used, just to make sure nothing subsequent is getting picked up
and to be clear - everything is working, except the wrong content-type is coming back and screwing up the response?
b
I'm getting back the wrong content type, and it's coming back with no data.
m
also, we usually explicitly set
cfheader( name="Access-Control-Allow-Origin", value="#getOrigin()#" );
in
Application.cfc
within
setupResponse()
might want to see if that gets picked up
b
The snippet I show above uses the header part of renderdata to do that. Works in dev, but not in prod.
I tried setting the header before calling renderdata but it didn't matter. I've tried setting it in .htaccess and that worked, but I was still getting text/html back as the content type.
I'll try some of these suggestions in a minute. I'm at the bus stop waiting for my kid right now.
vary: origin - no go. return after renderData - no go.
s
The actual JSON response should not need the ACAO header because the preflight request is separate from the POST request that follows it. The way CORS works (when it works properly) is: • browser decides to check CORS for a given request and sends an OPTIONS preflight request • the framework should handle OPTIONS directly itself, returning the ACAO and other headers -- and should not invoke any of your handlers -- the OPTIONS response will have no data, just headers • the browser looks at the OPTIONS response and, if it likes it, sends the original (POST) request • the framework routes that POST and your handler runs "as normal" If you're looking at devtools, you should see two requests when CORS checking happens: • the OPTIONS request -- for which the response should have no data (and the content-type should not matter) -- followed by • the POST request -- which should respond with data and the appropriate content-type
A lot of people think their app needs to handle OPTIONS as if it were the actual POST request but to "also add ACAO and other headers" but that is not correct.
b
right. the OPTIONS request is all good. I can see that in the network requests.
the subsequent GET request is where I'm having an issue.
s
And what exactly does the OPTIONS request respond with? What headers? (and, to confirm, no body, right?)
(you should not be setting ACAO headers when trying to return your JSON BTW)
b
I understand there are a number of things I "shouldn't have to" do here
As far as the access control headers on the OPTIONS response:
Copy code
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Content-Type,sentry-trace
Access-Control-Allow-Methods: OPTIONS,POST,GET
Access-Control-Allow-Origin: mydomainhere
Access-Control-Max-Age: 1728000
it returns text/plain, no data
It almost feels like something is unsetting the header but only in one environment
If I set the ACAO header to the right origin in .htaccess, I can see it in my GET response, but I'm still getting back text/html as the content type
If I turn preflight options off in FW1 and set the headers in .htaccess, I get the same result. I just can't get the controller to respond with JSON.
well, good news and bad news.
Good news - the framework works like it should
bad news - I'm an idiot and had an abort somewhere so the actual controller item never got to run
It's all working now
👍🏻 1
s
Thanks for reporting back on that and I'm a) glad the framework is still working but b) sorry you had to spin all those cycles to find the bug!