NancyFx / Nancy

Lightweight, low-ceremony, framework for building HTTP based services on .Net and Mono
http://nancyfx.org
MIT License
7.15k stars 1.47k forks source link

CORS and Custom Headers #1947

Open linvi opened 9 years ago

linvi commented 9 years ago

Hello,

First of all thank you so much for this great framework. I really appreciate the fact that the library is divided in multiple modules and that we can handle what the server does. This is way better than Microsoft WebAPI for sure.

Now concerning my problem. I am using Nancy to implement a REST API. This API should allow cross domain requests. Everything is working fine with normal webrequests. But if I add a custom header to my query, Nancy totally ignores the request and I never receive any event informing that a request has been received by Nancy.

Please find more information below concerning my code.

Here is my NancyModule :

public AuthModule() : base("/auth/")
{
    Before += ctx =>
    {
        return null;
    };

    Post["/login"] = x =>
    {
          return new Response { StatusCode = HttpStatusCode.OK };
    };

The before event is never raised if a custom header is added to the WebRequest.

In my bootstrapper I override the RequestStartup to initialize the CORS headers as followed:

pipelines.AfterRequest.AddItemToEndOfPipeline(ctx =>
{
        ctx.Response.Headers.Add("Access-Control-Allow-Origin", "http://localhost:8080");
        ctx.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,DELETE,PUT,OPTIONS");
        ctx.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
        ctx.Response.Headers.Add("Access-Control-Allow-Headers", "Accept,Origin,Content-type,MY_HEADER");
        ctx.Response.Headers.Add("Access-Control-Expose-Headers", "Accept,Origin,Content-type,MY_HEADER");
});

As you can see in the 2 last lines, I add a custom header to be available in cross domain requests. I then use the stateless authenticate as followed:

StatelessAuthentication.Enable(pipelines, configuration);

Ajax WebRequest :

$.ajax({
                beforeSend : function(xhr) {
                  xhr.setRequestHeader('MY_HEADER', 'my value');
                },

                method: httpMethod,
                url: "http://localhost:8081/auth/login",
                data: data,
                dataType: 'json',
                accept: {
                    json: 'application/json'
                },
                async: true,

                success: function (result) {
                    if (successCallback != null) {
                        successCallback(result);
                    }
                },
                error: function (result) {
                    if (failureCallback != null) {
                        failureCallback(result);
                    }
                },

                crossDomain : true,

                xhrFields: {
                    withCredentials: true
                }
            });

If the line xhr.setRequestHeader('MY_HEADER', 'my value'); is removed the request is received by Nancy. If a header is added the request is never received. Or at least I never get any event raised.

When a header is added this result in the following : "XMLHttpRequest cannot load http://localhost:8081/auth/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access."

Finally here are the headers displayed in Chrome:

// Request Headers
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:fr,en-US;q=0.8,en;q=0.6
Access-Control-Request-Headers:accept, content-type, my_header
Access-Control-Request-Method:POST
Cache-Control:no-cache
Connection:keep-alive
DNT:1
Host:localhost:8081
Origin:http://localhost:8080
Pragma:no-cache
Referer:http://localhost:8080/
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.81 Safari/537.36

// Response Headers
Allow:OPTIONS, TRACE, GET, HEAD, POST
Content-Length:0
Date:Thu, 28 May 2015 19:55:45 GMT
Public:OPTIONS, TRACE, GET, HEAD, POST
Server:Microsoft-IIS/10.0
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?QzpcVXNlcnNcVGhvbWFzXERldmVsb3BtZW50XEhlcmVBbmRUaGVyZVxIZXJlQW5kVGhlcmUgLSAwLjFcSGVyZUFuZFRoZXJlLldlYkFwaVxhdXRoXGxvZ2lu?=

You can see that no Access-Control-Allow-Origin is present in the response headers.

I greatly appreciate your help. Linvi

phillip-haydon commented 9 years ago

Interesting! Lots of informations!

linvi commented 9 years ago

Hi phillip,

Any idea what could be going wrong? I don't know Nancy well enough to know how to retrieve ALL the WebRequests received by the server.

Thanks for looking into it. Linvi

phillip-haydon commented 9 years ago

I'm still at work so I haven't looked into it yet. Just happy you gave a lot of information. I'll take a closer look this weekend to see if I can reproduce and figure out whats going on.

xt0rted commented 9 years ago

This stack overflow answer looks like it might be what you need.

linvi commented 9 years ago

Hi,

Thanks for your answer.

I already looked at this post (and tried it). The problem here is that the WebRequest is never handled by Nancy. This code is never invoked and yet Nancy returns a status code of 200 without the additional headers that this solution or mine try to add.

Cheers, Linvi

linvi commented 9 years ago

Hi here,

Any luck with identifying what could be going wrong with this issue?

Cheers, Linvi

phillip-haydon commented 9 years ago

My flatmate has my old laptop and I can't buy my new one because apple has no stock. :( so I'm waiting for him to get home so I can steal the laptop for an hour.

phillip-haydon commented 9 years ago

Sorry @linvi, I just don't have a laptop at the moment with OSX to test on :(

I am stealing it for the weekend tho because I'll be traveling to Thailand so I'll try reproduce then.

linvi commented 9 years ago

Hi,

No worries, but just to be clarify, I am not reproducing this issue on OSX, I have this issue on Windows 8.1.

Cheers

phillip-haydon commented 9 years ago

Ahhh I've confused this with another bug I'm trying to reproduce with Xamarin on OSX.

SORRY!

I'll try and look at this tonight then.

linvi commented 9 years ago

Any luck?

phillip-haydon commented 9 years ago

I haven't been able to reproduce it yet. Still trying. I only got to spend an hour on it last night.

BUT I have started investigating.

linvi commented 9 years ago

Hi, Thanks for taking the time to look into it. Do you want me to create a repro project?

phillip-haydon commented 9 years ago

It you could that would be great. Sorry I am in Thailand.

Sent by Outlook for Android

On Mon, Jun 8, 2015 at 3:01 AM -0700, "linvi" notifications@github.com wrote:

Hi, Thanks for taking the time to look into it. Do you want me to create a repro project?

— Reply to this email directly or view it on GitHub.

evicent commented 8 years ago

I'm still awating for this!

chenzhekl commented 7 years ago

I guess it's because you didn't handle preflight sent by the browser.

gilbertogwa commented 7 years ago

I was able to pass through CORS using the code below in the Configure method:

`

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public virtual void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        // Shows UseCors with CorsPolicyBuilder.
        app.UseCors(builder =>
           builder.WithOrigins(new[] { "http://localhost:4200" }).AllowAnyHeader()
                    .AllowAnyMethod()
                    .AllowCredentials()
           );

        app.UseOwin(a => a.UseNancy(b => b.Bootstrapper = new NancyBootstrap(this.Container)));

    }

`