redstone-dart / redstone

A metadata driven microframework for Dart.
http://redstone-dart.github.io/redstone
MIT License
342 stars 42 forks source link

Body as JSON Question #9

Closed digizen closed 10 years ago

digizen commented 10 years ago

I'm not sure if I'm doing something wrong or I've stumbled into a bug.

Server-side, this works fine:

@app.Route("/user/login", methods: const [app.POST])
Map Login() {
  print("inside route.");
  return null;
}

Same thing, with a "body" request annotation fails:

@app.Route("/user/login", methods: const [app.POST])
Map Login( @app.Body(app.JSON) Map json) {
  print("inside route.");
  return null;
}

The error message I receive (client-side) is below. The server doesn't respond with any error at all.

Failed to load resource: the server responded with a status of 400 (Bad Request) http://127.0.0.1:8080/user/login Instance of '_XMLHttpRequestProgressEvent'

STACKTRACE: null

This is my client-side code:

    var url = "http://127.0.0.1:8080/user/login";

    HttpRequest.request(url, method:'POST', sendData: JSON.encode(
        {"username" : "test",
         "password" : "ok" });

Can you please assist?

Thanks, Greg

luizmineo commented 10 years ago

Hi Greg,

On the client-side, you need to set the content type of the request:

    var url = "http://127.0.0.1:8080/user/login";

    HttpRequest.request(url, method:'POST', 
        requestHeaders: {"content-type": "application/json"},
        sendData: JSON.encode(
            {"username" : "test",
             "password" : "ok" });

I hope that helps.

luizmineo commented 10 years ago

Also, when you stumble on a problem like this, you can change the log level:

import 'package:logging/logging.dart';

main() {
  app.setupConsoleLog(Level.ALL);
  ...
}

So Redstone will give you some hints on why a request is returning an error code.

digizen commented 10 years ago

Thank you for the help. It's now giving me a different error (405). Here's the code (client-side):

    HttpRequest.request(url, method:'POST', requestHeaders: {"content-type": "application/json"}, 
        sendData: JSON.encode(
        {"username" : "test",
         "password" : "ok" })

The error message on the client:

Failed to load resource: the server responded with a status of 405 (Method Not Allowed) http://127.0.0.1:8080/user/login

The server, with the elevated log level (Level.ALL) is still not supplying enough info to diagnose the problem:

FINE: 2014-05-15 08:13:01.354: Received request for: /user/login FINER: 2014-05-15 08:13:01.362: Invoking interceptor: .handleResponseHeader adding cors headers. FINER: 2014-05-15 08:13:01.396: Closed request for: /user/login

Thanks for any insight you can shed into this.

Greg

luizmineo commented 10 years ago

It seems Redstone is not generating a log message when a 405 error is returned... I will fix that in a future release.

But I could not reproduce this specific error. Can you send me your script, so I can run it at my side?

digizen commented 10 years ago

Sure. I created a test project on github:

https://github.com/digizen/redstone_test/tree/master/redstone_test

Thanks again for your help, Greg

luizmineo commented 10 years ago

It seems a issue with CORS.

When your client code sends the request, what the browser actually sends is a request with the OPTIONS method. Since your route only accepts POST, the server responds with a 405 status code.

So, I changed your interceptor to:

@app.Interceptor(r'/.*')
handleResponseHeader() {
  addCorsHeaders(app.request.response.headers);
  if (app.request.method == "OPTIONS") {
    app.chain.interrupt();
  } else {
    app.chain.next();
  }
}

And it seems to work fine.

Let me know if this solves your problem.

Edit: About CORS: http://www.html5rocks.com/en/tutorials/cors/#toc-adding-cors-support-to-the-server

digizen commented 10 years ago

Thanks, that fixed the issue!

Can you let me know if my understanding of this is correct?

  1. The app.chain.interrupt() request terminates the request and allows the "preflight" CORS packet to succeed?
  2. A second packet is sent, this time with the POST method, and this is then handled by the Login method.

Thanks again, Greg

luizmineo commented 10 years ago

yes, that's correct.

luizmineo commented 10 years ago

I opened a new issue ( #10 ) concerning the log problem.