framework-one / fw1

FW/1 - Framework One - is a lightweight, convention over configuration, MVC application framework for ColdFusion / CFML.
http://framework-one.github.io
Other
373 stars 141 forks source link

Fw/1(Lucee) - Ajax request failed by CORS policy #528

Closed asimakos closed 3 years ago

asimakos commented 3 years ago

I have got the following ajax request in Framework7 in order to get back json data in FW/1 (Lucee 5.2.9), but unfortunately i get error due to CORS policy via Chrome browser.

app.request({
      url:"http://127.0.0.1:49820/",
      type:"POST",
      data:JSON.stringify({
        "username":username,
        "password":password
      }),
      dataType:"json",
      success:function(result){
         console.log(result);
      }
});

I have used variables.fw.renderData( "json", rc.user_info); in my controller code with no success, but additionally i have used <cfheader name="Access-Control-Allow-Origin" value="*"> in the appropriate template file also with no success. Any idea how i enable CORS policy in FW/1 (Lucee 5.2.9)?

I have posted the same question in Stackoverflow post, if you do not mind.

Regards

tonyjunkes commented 3 years ago

What version of FW/1 are you using? I assume the latest?

I know nothing about how Framework7's ajax features work, but I would try setting preflightOptions = true, if you haven't already, in your FW/1 framework settings in Application.cfc and see if that remedies your issue.

Check out the OPTIONS Support section of http://framework-one.github.io/documentation/4.3/developing-applications/#options-support

Let me know if that helps.

asimakos commented 3 years ago

I have got the following Framework7 ajax request settings

app.request({
  url:"http://127.0.0.1:49820/index.cfm/user/login/",
  type:"POST",
  data:JSON.stringify({
    "username":username,
    "password":password
  }),
  crossDomain: true,
  xhrFields: { withCredentials: false },
  headers: {
   'Access-Control-Allow-Origin': '*',
   'Access-Control-Allow-Methods':'GET,HEAD,OPTIONS,POST,PUT',
   'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, Authorization',
   'Content-type': 'text/javascript; charset=utf-8',
  },
  dataType:"jsonp",
  success:function(result){
      console.log(result);
  }

 });

I have got the following ajax request in Framework7 in order to get back json data in FW/1 (4.2) (Lucee 5.2.9), but unfortunately i get error due to CORS policy via Chrome browser.

app.request({ url:"http://127.0.0.1:49820/index.cfm/user/login/", type:"POST", data:JSON.stringify({ "username":username, "password":password }), crossDomain: true, xhrFields: { withCredentials: false }, headers: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods':'GET,HEAD,OPTIONS,POST,PUT', 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, Authorization', 'Content-type': 'text/javascript; charset=utf-8', }, dataType:"jsonp", success:function(result){ console.log(result); }

}); In my Fw/1 (4.2) Application.cfc, i have got the following settings:

variables.framework =   {
      preflightOptions = true,
      generateSES = true,
      routes= [
        { "$POST/user/login/" = "/main/get" }
        ] 
    };

and in my main Controller get action i get json via

rc.user_info = variables.userService.login(rc.dsn,rc.username,rc.password);
variables.fw.renderData( "json", rc.user_info);

Unfortunately i receive the following message

Access to XMLHttpRequest at 'http://127.0.0.1:49820/index.cfm/user/login/' from origin 'http://localhost' has been blocked by CORS policy: Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response.

Any idea that could help me?

Regards

tonyjunkes commented 3 years ago

Ok. Thanks for the details. You'll want to look at what headers are coming back in the request to confirm what's expected. You can do that in Chrome Dev Tools by looking at the request in the Network tab. Check what Access-Control-Request-Headers is passing.

But you can also try this...

In your app.request block, can you try adding Access-Control-Request-Method, Access-Control-Request-Headers to Access-Control-Allow-Headers

So: 'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, Authorization, Access-Control-Request-Method, Access-Control-Request-Headers'

asimakos commented 3 years ago

Regarding specific header information that i receive:

header

and my console error message:

cors

Regards

tonyjunkes commented 3 years ago

I'm running out of initial suggestions without having an example of your app to test with. It's been a while since I've done any REST work in FW/1 so I'm sure this is a matter of something not being setup.

My next suggestion is to set your allowed headers in the FW/1's framework settings. You can do this by defining optionsAccessControl.headers = "your, headers, here". This is all mentioned in the link I shared previously.

You can defined the optionsAccessControl struct as a whole if you'd like and set the other keys as well.

optionsAccessControl = {
  origin: "",
  headers: "",
  credentials: true/false,
  maxAge: 12345
}
asimakos commented 3 years ago

Thanks for your suggestion! The problem is what exact values i have to pass to this struct defined in Application.cfc to work properly. I could email you an example (both client and server side code), if there is no problem to you, in order to see clearly my problem as to be honest with you this is my first fw/1 project. Regards

tonyjunkes commented 3 years ago

Sure no problem, you can email it to tony@tonyjunkes.com.

asimakos commented 3 years ago

I have already sent you the necessary files (https://we.tl/t-oDTBwV4unn). Thanks again for the great help!

tonyjunkes commented 3 years ago

Thanks. When I have some time I will take a look.

tonyjunkes commented 3 years ago

Thanks for providing code to reproduce the issue. Here's what you can do to get things working with CORS...

In Application.cfc, include the following framework settings:

generateSES = true,
SESOmitIndex = true,
routes= [
    { "$POST/user/login/" = "/main/get" }
],
preflightOptions = true,
optionsAccessControl = {
    origin: "*",
    headers: "Origin, X-Requested-With, Content-Type, Accept, Authorization, Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin"
}

In the get method of main.cfc you will need to pass the origin header with your response:

variables.fw.renderData( "json", rc.user_info).header( "Access-Control-Allow-Origin", "*" );

Note: For security reasons, it's best practice to not allow "*" and instead only allow the domain that is calling/responding. (Example: http://127.0.0.1:12345)

That should be enough to get your JS talking to FW/1.

asimakos commented 3 years ago

Thanks a lot! No CORS policy issues now.

I would like to mention a slight issue with SESOmitIndex = true regarding #buildURL('main.other')#. I get the following url: /main/other, but when i click on it i receive error. In the other url case index.cfm/main/other (without SESOmitIndex=true), it works fine for me especially when i click it.

Thanks again for your assistance regarding CORS policy, otherwise my entire project definitely would have failed.

tonyjunkes commented 3 years ago

You're welcome.

If you're not having the web server also account for index.cfm being omitted then I can see why there could be issues. I think I set it to true while I was testing some things. No problem if you're not using it like that and want it to be left false.

asimakos commented 3 years ago

I am just using lucee server, is there any problem to enable it or not and how? Thanks again.

tonyjunkes commented 3 years ago

It's not a problem if you do not want or need to omit index.cfm in your URL. That's completely up to you and your project's requirements. Typically, when removing index.cfm from a URL, it is done using URL rewriting capabilities of the web server (IIS, nginx, Apache, CommandBox/RunWAR, etc.) which goes slightly beyond Lucee and FW/1.

tonyjunkes commented 3 years ago

@sneiland I think this issue can be closed.