9

I've got an odd case where my jquery.post returns a code #200 (OK) but the error-handler is hit.

This is my MVC WebAPI serverside code (all it does is returning code #200 OK):

[HttpPost]
public HttpResponseMessage Post(T input)
{
    //_handler.Create(input);

    return Request.CreateResponse(HttpStatusCode.OK);
}

and this is my client script

ServerAccess.prototype.Save = function (m) {

            $.post("http://localhost:55482/M/", m)
            .success(
                function (o) {
                    alert("success");
                })
            .error(
                function (xhr, textStatus, errorThrown) {
                    if (typeof console == 'object' && typeof console.log == 'function') {
                        console.log(xhr);
                        console.log(textStatus);
                        console.log(errorThrown);
                    }
                }
            );
        };

The console output in Firebug is:

POST http://localhost:55482/M/ 200 OK 894ms

Headers


Response Headers

Content-Length 6

Content-Type application/json; charset=utf-8

Date Sun, 28 Oct 2012 18:55:17 GMT

Server Microsoft-HTTPAPI/2.0


Request Headers

Accept /

Accept-Encoding gzip, deflate

Accept-Language nb-no,nb;q=0.9,no-no;q=0.8,no;q=0.6,nn-no;q=0.5,nn;q=0.4,en-us;q=0.3,en;q=0.1

Connection keep-alive

Content-Length 21

Content-Type application/x-www-form-urlencoded; charset=UTF-8

Host localhost:55482

Origin null

User-Agent Mozilla/5.0 (Windows NT 6.2; WOW64; rv:16.0) Gecko/20100101 Firefox/16.0

and

Object { readyState=0, status=0, statusText="error"}

error

(an empty string)

I've browsed around and seen others had similar problems, usually malformed JSON in the response. Since I only return a 200 OK an no content this doesn't seem to fit my case. However I did try to return a empty object like so

var o = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(new T());

return Request.CreateResponse(HttpStatusCode.OK, o);

The serverside runs from Visual Studio 2012, and the client is just a standalone .html with some .js files. Also, with a breakpoint in VS I know the request is received by the server, and with Postman for Chrome everyting works great.

So the question is of course: what am I doing wrong here? Why is the error-handler hit?

Thanks!

kamiar3001
  • 2,646
  • 4
  • 42
  • 78
Andreas
  • 5,501
  • 2
  • 20
  • 23
  • Response header `Content-Type application/json; charset=utf-8` for text? – charlietfl Oct 28 '12 at 19:36
  • as in saying it should be `text/plain` or something? – Andreas Oct 28 '12 at 19:44
  • depends on what ultimate goal of API is. If you intend to send json, set `dataType` option of `$.post` as `json` and send some dummy json instead of text. $.ajax is likely reading that header currently and trying to parse json that doesn't exist and no dataType is set in $.post – charlietfl Oct 28 '12 at 19:48
  • still get this error.. :( could it be a problem of cross-domain perhaps? personally i think not as the request is received at the server, or am i wrong in that assumtion? how do i implements jsonp as a post, is it event possible? – Andreas Oct 29 '12 at 10:12
  • is it same domain , port and protocol ? If not API needs to send jsonp or use a proxy on your domain to retrieve from API and send to ajax. Do you control the API? – charlietfl Oct 29 '12 at 13:01
  • it is not the same domain. It is a hobby project (my get rich scheme) of mine using Cordova/PhoneGap (a standalone .html with some .js-files) with a REST backend in C#. So everything is under my controll really. I've been able to use jsonp for a GET operation, but I dont understand what to do when I need to do a POST (as jsonp is only GET)? – Andreas Oct 29 '12 at 13:39
  • can get the json using Yahoo YQL which will act as proxy and return jsonp which can be handled cross domain if you don't have access to server of your own to create your own proxy. With javascript can only do get cross domain...why do you need POST? – charlietfl Oct 29 '12 at 13:42
  • well, I need a POST to post user input to the server – Andreas Oct 29 '12 at 13:48
  • API won't accept GET data? If not you will defintiely need your own server proxy to make a POST – charlietfl Oct 29 '12 at 13:49
  • the API does accept a GET with jsonp. But that's for retreiving data. I need to post data to the server to create and update databaserows. Are you saying I should use GET to send data to the server, I assume with data in the querystring of the url? Problem with this is the limited size of the url as the data I want to send can be rather big. However, I am able to send data to the server as a regular POST, but when the response returns the error-handler of the jquery.post() is hit, and it's this I want to avoid and don't understand how to fix. – Andreas Oct 29 '12 at 13:56
  • if you have control over API and can enable CORS might be able to do it somehow. I am uncertain. – charlietfl Oct 29 '12 at 14:01
  • ok, i'll look into that. thanks for all the input man! – Andreas Oct 29 '12 at 14:03
  • What was the solution, did you find one? – tatigo Oct 08 '13 at 16:26

4 Answers4

3

Try this instead:

ServerAccess.prototype.Save = function (m) {
    $.ajax({
        "type": "POST",
        "url": "http://localhost:55482/M/",
        "data": m,
        "dataType": "json",
        "success": function (data, textStatus, xhr) {
            alert("success");
        },
        "error": function (xhr, textStatus, errorThrown) {
            if (typeof console === 'object' && typeof console.log === 'function') {
                console.log(xhr);
                console.log(textStatus);
                console.log(errorThrown);
            }
        }
    });
};

This allows you to set an expected return MIME type of application/json.

UPDATE

If you're running your standalone HTML page on http://localhost:55482, then it won't be cross-domain. If you're running it on file:///C:/Users/.../Desktop/test.htm or somewhere else, then it will be a cross-domain request. http versus https: also makes the difference.

A jsonp request is a GET request and cannot be a POST. This is because jsonp requests are implemented by adding a <script> element to the page with the source set to your url, with data appended to the querystring (plus a timestamp parameter). Any POST requests that expect a jsonp return should be automatically converted to GET requests.

Finally, since your routine expects data back, you'll need to return some actual data as jQuery will try to parse the JSON that's returned into an object (which it cannot do if no data is returned) and will throw an error if the data cannot be parsed.

Try changing your response message to:

String o = "success";
System.Web.Script.Serialization.JavaScriptSerializer ser = new System.Web.Script.Serialization.JavaScriptSerializer();

return Request.CreateResponse(HttpStatusCode.OK, ser.Serialize(o));
pete
  • 24,141
  • 4
  • 37
  • 51
  • still get the error. i do notice however that even though i return an empty object (on server: `new T()` and `new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(new T())` the Response-tab in the Console-tab in Firebug is empty. Is it suppose to be the dummy-object? – Andreas Oct 28 '12 at 20:24
  • 1
    could it be a problem of cross-domain perhaps? personally i think not as the request is received at the server, or am i wrong in that assumtion? how do i implements jsonp as a post, is it event possible? – Andreas Oct 29 '12 at 10:11
0

As I understood you need cross-domain so you should have a handler or service caller

read THIS it might be useful for you.

Add JsonpFormatter as filter in application start then you can enjoy jsonp.

kamiar3001
  • 2,646
  • 4
  • 42
  • 78
0

It's quite possible it has something to do with the empty response you are sending. See this bug report: http://aspnetwebstack.codeplex.com/workitem/1664

You can solve this by setting an empty string as response.

return Request.CreateResponse(HttpStatusCode.OK, "");

The bug report contains a workaround, which involves creating a message handler which adds an empty string where content == null.

public class HttpResponseMessageHandler : DelegatingHandler
    {
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
        {


            var response = await base.SendAsync(request, cancellationToken);

            if (response.Content == null && request.Headers.Accept.Any(a => a.MediaType == "application/json"))
            {
                var content = new StringContent("{}");
                content.Headers.ContentLength = 2;
                content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
                response.Content = content;
            }

            return response;
        }
    }
Robin van der Knaap
  • 4,060
  • 2
  • 33
  • 48
0

I have just encountered this issue while using a JSON request to a WebApi 2 service. For me, it was solved by simply changing the parameter list for the success and error functions (no changes were needed on the WebApi side)

I changed my code from this

success: function (data) { alert(data); },
error: function (error) { jsonValue = jQuery.parseJSON(error.responseText); }

to this

success: function (data, textStatus, xhr) 
{ 
  alert("data: " + data + "\ntextStatus: " + textStatus + "\nxhr: " + xhr);
},
error: function (xhr, textStatus, errorThrown)
{                       
  alert("xhr: " + xhr + "\ntextStatus: " + textStatus + "\nerrorThrown " + errorThrown);
}

Note the change in the arguments list

Alex Hopkins
  • 872
  • 9
  • 11