ipkn / crow

Crow is very fast and easy to use C++ micro web framework (inspired by Python Flask)
BSD 3-Clause "New" or "Revised" License
7.48k stars 891 forks source link

kept receiving a 404 while trying to access a basic crow server from a js fetch request #264

Closed percyteng closed 6 years ago

percyteng commented 6 years ago

Here is my basic crow server

crow::SimpleApp app;

CROW_ROUTE(app, "/")
.methods("GET"_method)
([](){
        crow::json::wvalue x;
        x["message"] = "Hello, World!";
        return x;
});
CROW_ROUTE(app, "/api")([](){
    crow::json::wvalue x;
    x["message"] = "Hello, World!";
    return x;
});

app.port(4500).multithreaded().run();

I was trying to send a standard fetch request from Javascript, however, I kept receiving a 404 request from it. When I tried to access the crow server on both browser and postman, they work! So I am not sure if there is something wrong with my js fetch or just crow itself. Here is my fetch

return fetch('http://localhost:4500', { method: 'GET', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', } }) .then((response) => { console.log(response) if (response.status != 200){ console.log('errors') return } else{ return response.json() } }) .then((responseJson)=>{ console.log(responseJson) }) .catch((error) => { console.error(error); });

Shravan40 commented 6 years ago

You need to add cross origin support.

percyteng commented 6 years ago

@Shravan40 Can you please share me an example of how to enable the cors in crow? Thanks!

Shravan40 commented 6 years ago

You can try adding res.add_header("Access-Control-Allow-Origin", "*"); and, possibly, by a few: res.add_header("Access-Control-Allow-Headers", "Content-Type");

percyteng commented 6 years ago

@Shravan40 I am not sure where to add this line tho? I don't see variable res anywhere in either crow server or my js request

Shravan40 commented 6 years ago

@percyteng : Please go through this issue thread.

percyteng commented 6 years ago

@Shravan40 if you are saying adding the header to my js request, I have tried plenty of times. But my issue doesn't seem like it's related to cross-origin at all especially when I have this chrome extension to explicitly enable no cors on any request.

percyteng commented 6 years ago

@Shravan40 I think I am getting what you are saying

Tried to do this CROW_ROUTE(app, "/") .methods("GET"_method) ([](const crow::request& req){ const crow::response& res; res.add_header("Content-Type", "text/plain"); crow::json::wvalue x; x["message"] = "Hello, World!"; // return x; }); but the add_header gives me an error Invalid arguments ' Candidates are: void add_header(std::1::basic_string<char,std::__1::char_traits,std::1::allocator>, std::1::basic_string<char,std::__1::char_traits,std::1::allocator>) ' I looked into add_header function and seems like my parameters should be right

pierobot commented 6 years ago

You're getting that error because you're trying to access a non-const method in a const variable.

const crow::response& res; // <--- const variable - and is an invalid reference
res.add_header("Content-Type", "text/plain"); // <--- add_header modifies res (non-const method)

The correct way to access the crow::response is to do use the following

CROW_ROUTE(app, "/")([](const crow::request&, crow::response& response)
{
    response.add_header(...);

    // write your data with this
    response.write(...);

    return response;
});
percyteng commented 6 years ago

@pierobot Hi! I actually tried that before, but I was getting these errors error: static_assert failed "Handler function with response argument should have void return type" and error:call to implicitly-deleted copy constructor of 'crow::response' Seems like it wants me to return nothing when there is response argument.

pierobot commented 6 years ago

Oh sorry, it's been a while.

This should do the trick

CROW_ROUTE(app, "/")([](const crow::request&, crow::response& response) -> void
{
    response.add_header(...);

    // write your data with this
    response.write(...);
    response.end();
});

I believe you can also do

CROW_ROUTE(app, "/")([]()
{
    crow::response response;
    response.add_header(...);

    // write your data with this
    response.write(...);

    return response;
});
percyteng commented 6 years ago

@pierobot that worked! but my issue is still not resolved right now my default route is like this CROW_ROUTE(app, "/") .methods("GET"_method) ([](const crow::request&, crow::response& response){ string key = "Access-Control-Allow-Origin"; string value = "*"; response.add_header(key, value); crow::json::wvalue x; x["message"] = "Hello, World!"; response.write("hehehe"); response.end(); });

but I am still getting the 404 error. and if I disabled the chrome extension for cors. I am also getting the Access-Controll-Allow-Origin error: No 'Access-Control-Allow-Origin' header is present on the requested resource. This error should be resolved by adding the header to res in crow response though.

pierobot commented 6 years ago

Perhaps https://github.com/ipkn/crow/issues/207#issuecomment-284045848 will help you

percyteng commented 6 years ago

@pierobot @Shravan40 is it possibly related to OPTIONS? Looking at the log, instead of getting a GET request, seems like my crow is getting an OPTIONS request which triggers a 404. But I have indeed sent a GET request from my js fetch tho

pierobot commented 6 years ago

Yes that seems to be the case. The docs imply that an OPTIONS request will be sent BEFORE the other method.

percyteng commented 6 years ago

@pierobot I think I found a solution! I added both request types to my handler CROW_ROUTE(app, "/") .methods("OPTIONS"_method, "GET"_method) Seems to work!

Really appreciate the help!