Rails: "head :ok" interpreted as "ajax:error" [duplicate] - ruby-on-rails-3

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
jquery doesn’t call success method on $.ajax for rails standard REST DELETE answer
I respond to a remote-link (data-remote="true" data-type="json") and output
format.json { head :ok }
in my Rails (3.2.6) controller, which creates this header:
Status Code:200 OK
...
Connection:keep-alive
Content-Length:1
Content-Type:application/json; charset=utf-8
Server:thin 1.4.1 codename Chromeo
Set-Cookie: ... path=/; HttpOnly
X-UA-Compatible:IE=Edge
...
In my JavaScript file ajax:complete is triggered and outputs 200 (data.status).
$( '#myElement' ).on( 'ajax:complete', function( e, data ) {
console.log( data.status );
});
data looks like this:
...
readyState: 4
responseText: " "
setRequestHeader: function ( name, value ) {...
state: function () {...
status: 200
statusCode: function ( map ) {...
statusText: "OK"
...
Looks pretty good to me...
The problem
Instead of ajax:success, jQuery (jquery-ujs) executes ajax:error and I have no idea why since no error is given.
I have looked into alot of discussions, but this way always seemed to be the solution, not the problem. Thank you for any help!

Answered here.
jQuery is expecting a JSON response. "head :ok" has a single space for the response body, so jQuery fails to parse the JSON response so it still considers the 200 status code an error.
You can have Rails respond with head :no_content which has an empty body or a render :json=>true
This was discussed in Rails here.
The reason for the single space in head :ok in Rails is a workaround in an old Safari bug.

Related

How can I properly send a batch request using UCWA 2.0?

I am writing a UCWA application to receive each user's presence and note. At the moment, I subscribe to all my desired contacts, I initiate my event stream and then I receive around 200 events. I loop through them to receive my contacts presence and notes using a for loop, meaning I send around 100 requests, which, according to Microsoft documentation, can drain battery on mobile devices or impact performance. I would like to use batching to fix this problem.
onEvent(events) {
for (var i in events) {
const event = events[i]
switch (event.link.rel) { // 250 events filtered down to around 100
case 'contactPresence':
case 'presence':
this.setPresence(event.link.href, this.getUser(event))
break
case 'contactNote':
case 'note':
this.setNote(event.link.href, this.getUser(event))
break
case 'presenceSubscription':
...
break
}
}
}
After searching through Microsoft's documentation, I couldn't find any help on how to format a batch request. I tried following one of the examples provided, but I received a 400 error like this:
{
"code":"BadRequest",
"message":"Your request couldn\u0027t be completed."
}
Eventually I tried sending a batch following formatting that I've seen from this post, like so:
batch() {
const boundary = Date.now()
fetch(this.hub + this.response._links.batch.href, {
method: 'POST',
headers: {
Accept: 'multipart/batching',
Authorization: `Bearer ${this.token}`,
'Content-Type': `multipart/batching;boundary=${boundary}`
},
body: `--${boundary}\r\nContent-Type: application/http; msgtype=request\r\n\r\nGET ${this.response._links.self.href + '/people/contacts'} HTTP/1.1\r\nAccept: application/json\r\nHost: ${this.hub}\r\n\r\n--${boundary}--`
}).then(r => r.json())
.then(data => console.log(data))
}
Here is the request payload:
--1557482296198
Content-Type: application/http; msgtype=request
GET /ucwa/oauth/v1/applications/103357029549/people/contacts HTTP/1.1
Accept: application/json
Host: https://webpoolam41e02.infra.lync.com
--1557482296198--
This returns a 500 error, however, like this:
{
"code":"ServiceFailure","message":"Your request couldn\u0027t be completed.",
"debugInfo":{
"errorReportId":"8d6499597a54443495627bd2b3e3c5b6"
},
"reasonId":"1000005"
}
I have spent a long time searching for an answer but I cannot find one that works.
Does anyone know how to properly format a batch request?
I have found an answer to my own question. It turns out that the final batch requires 3 line breaks:
\r\n\r\n\r\n
Rather than 2:
\r\n\r\n

Fetch returning empty blob although Content-Length correct

I am trying to retrieve a raw image in React Native through the fetch API, however, the result is empty even though the content headers show the request worked as expected.
While I understand that Expo provides the FileSystem.downloadAsync method for saving images, my endpoint (different from the example) requires a POST request meaning downloadAsync is not suitable.
When making the POST request, I get the same behaviour.
I have added the URL directly to an image element and it loads fine.
I have tried using text() and json() just to see if the result changes and in both instances the response was empty.
I have tried using an API Tester such as this: https://apitester.com/ and the result shows as I would expect
The following can be found in my snack
This is my request:
fetch('https://i.imgur.com/c9waLgY.jpg')
.then(result => {
console.log(result)
return result.blob()
})
.then(result => {
console.log('blob', result);
})
.catch(error => console.log(error));
Which returns the following headers:
content-type:"image/jpeg"
access-control-allow-methods:"GET, OPTIONS"
access-control-allow-origin:"*"
cache-control:"public, max-age=31536000"
x-cache-hits:"1, 1"
date:"Wed, 23 Jan 2019 21:10:36 GMT"
accept-ranges:"bytes"
etag:""bcb343578e3ea0d0d824f62e66d22bf0""
server:"cat factory 1.0"
age:"15302"
last-modified:"Wed, 23 Jan 2019 16:00:45 GMT"
x-timer:"S1548277836.140914,VS0,VE2"
content-length:"192289"
x-served-by:"cache-iad2133-IAD, cache-sea1051-SEA"
x-cache:"HIT, HIT"
And the following blob:
blobId:"a910e21b-80ba-44da-b6fa-20194b152538"
offset:0
size:0
type:""
lastModified:1548278321298
What am I doing wrong?

Webhook call failed. Error: Failed to parse webhook JSON response: Expect message object but got: [Chinese letters]

I'm building my own WebhookClient for dialog flow. My code is the following (using Azure Functions, similar to Firebase Functions):
module.exports = async function(context, req) {
const agent = new WebhookClient({ request: context.req, response: context.res });
function welcome(agent) {
agent.add(`Welcome to my agent!!`);
}
let intentMap = new Map();
intentMap.set("Look up person", welcome);
agent.handleRequest(intentMap);
}
I tested the query and the response payload looks like this:
{
"fulfillmentText": "Welcome to my agent!!",
"outputContexts": []
}
And the headers in the response look like this:
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
Date: Tue, 11 Dec 2018 18:16:06 GMT
But when I test my bot in dialog flow, it returns the following:
Webhook call failed. Error: Failed to parse webhook JSON response:
Expect message object but got:
"笀ഀ਀  ∀昀甀氀昀椀氀氀洀攀渀琀吀攀砀琀∀㨀 ∀圀攀氀挀漀洀攀 琀漀 洀礀 愀最攀渀琀℀℀∀Ⰰഀ਀  ∀漀甀琀瀀甀琀䌀漀渀琀攀砀琀猀∀㨀 嬀崀ഀ਀紀".
There's Chinese symbols!? Here's a video of me testing it out in DialogFlow: https://imgur.com/yzcj0Kw
I know this should be a comment (as it isn't really an answer), but it's fairly verbose and I didn't want it to get lost in the noise.
I have the same problem using WebAPI on a local machine (using ngrok to tunnel back to Kestrel). A friend of mine has working code (he's hosting in AWS rather than Azure), so I started examining the differences between our responses. I've notice the following:
This occurs with Azure Functions and WebAPI (so it's not that)
The JSON payloads are identical (so it's not that)
Working payload isn't chunked
Working payload doesn't have a content type
As an experiment, I added this code to Startup.cs, in the Configure method:
app.Use(async (context, next) =>
{
var original = context.Response.Body;
var memory = new MemoryStream();
context.Response.Body = memory;
await next();
memory.Seek(0, SeekOrigin.Begin);
if (!context.Response.Headers.ContentLength.HasValue)
{
context.Response.Headers.ContentLength = memory.Length;
context.Response.ContentType = null;
}
await memory.CopyToAsync(original);
});
This code disables response chunking, which is now causing a new and slightly more interesting error for me in the google console:
*Webhook call failed. Error: Failed to parse webhook JSON response: com.google.gson.stream.MalformedJsonException: Unterminated object at line 1 column 94 path $.\u0000\\"\u0000f\u0000u\u0000l\u0000f\u0000i\u0000l\u0000l\u0000m\u0000e\u0000n\u0000t\u0000M\u0000e\u0000s\u0000s\u0000a\u0000g\u0000e\u0000s\u0000\\"\u0000.\
I thought this could be encoding at first, so I stashed my JSON as a string and used the various Encoding classes to convert between them, to no avail.
I fired up Postman and called my endpoint (using the same payload as Google) and I can see the whole response payload correctly - it's almost as if Google's end is terminating the stream part-way through reading...
Hopefully, this additional information will help us figure out what's going on!
Update
After some more digging and various server/lambda configs, I spotted this post here: https://github.com/googleapis/google-cloud-dotnet/issues/2258
It turns out that json.net IS the culprit! I guess it's something to do with the formatters on the way out of the pipeline. In order to prove this, I added this hard-coded response to my POST controller and it worked! :)
return new ContentResult()
{
Content = "{\"fulfillmentText\": null,\"fulfillmentMessages\": [],\"source\": null,\"payload\": {\"google\": {\"expectUserResponse\": false,\"userStorage\": null,\"richResponse\": {\"items\": [{\"simpleResponse\": {\"textToSpeech\": \"Why hello there\",\"ssml\": null,\"displayText\": \"Why hello there\"}}],\"suggestions\": null,\"linkOutSuggestion\": null}}}}",
ContentType = "application/json",
StatusCode = 200
};
Despite the HTTP header saying the charset is utf-8, that is definitely using the utf-16le character set, and then the receiving side is treating them as utf-16be. Given you're running on Azure, it sounds like there is some configuration you need to make in Azure Functions to represent the output as UTF-8 instead of using UTF-16 strings.

Return a status 404 and an error message in response to an AJAX request, in Rails 3

I'm trying to get x-editable working (to allow inline form edits), using Rails 3.2
When I receive the post from the browser via AJAX, I need to be able to validate the form input and send back a response.
If its successful, I just need:
render :nothing => true
and this works ok.
If unsuccessful, according to their documentation I need to send back the equivalent of this PHP snippet:
header('HTTP 400 Bad Request', true, 400);
echo "This field is required!";
I cannot figure out how to do this in Rails.
If I try a simple render :status => 400, then my terminal output looks as follows:
Rendered text template (0.0ms)
Completed 200 OK in 34ms (Views: 1.3ms | ActiveRecord: 1.5ms)
And I can find no information on how to combine a 400 error with an actual message
How can I do this?
Try this:
render text: "This field is required!", status: :bad_request
What you're after is:
head :no_content, :status => :bad_request
This makes it explicit that you’re only generating HTTP headers
That PHP example doesn't include "This field is required!" in the response, instead it's printed out.
You'll want to respond with just an HTTP header with status code 400 Bad Request, as seen in:
header('HTTP 400 Bad Request', true, 400);
In Rails you can use this:
head :bad_request
# or
head 400
Or this, but it's less explicit to the reader that you're generating just the header:
render nothing: true, status: :bad_request
# or
render nothing: true, status: 400
If you do want to include a body with text in the response (so not just a header):
render text: "This field is required!", status: :bad_request
# or
render text: "This field is required!", status: 400

dojo/request/xhr returning xml instead of json

I'm using a simple dojo xhr request:
require(["dojo/query", "dojo/on", "dojo/dom-style", "dojo/request/xhr", "dojo/domReady!"],
function (query, on, domStyle, xhr) {
xhr("api/products", {
handleAs: 'json'
}).then(function (data) {
console.log('GOT DATA FROM DOJO XHR', data);
}, function (err) {
console.log('ERROR FROM DOJO XHR', err);
});
}
);
This works fine, but the data returned is as XML not JSON.
However, the same call in jQuery returns the data in JSON.
When I look at the headers, for the jQuery call it shows: Content-Type application/json; charset=utf-8, but for the dojo call it shows: Content-Type application/xml; charset=utf-8
I also added:
headers: { "Content-Type": "application/json; charset=uft-8" }
to the xhr parameters, but still no luck, it still returns xml.
What gives? How do you tell dojo xhr to handle it as json? I'm using dojo 1.8.3.
the server doesnt behvae like that by itself. check using firebug what dojo and jquery are requesting when they do a xhr. there has to be a param that tells the server that it is dojo or jquery. change that parameter.
dojo and jquery are the same, they are based on js and they both use xhr. please consider posting the exact request information for both.
Fixing server side works, but this is a band-aid solution. Server responds correctly to what it sees in the Accept header. Even if in Dojo xhr call you specify 'application/json', for some reason Firefox replaces it with 'text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8' or something similar. As a result .NET sends back XML instead of JSON. Does not happen in other browsers.
I am still looking at how to fix it in a correct way.
Update: I think I have an answer, but not sure why it fixes it. If I set headers value in xhr request like the following, then everything works in Firefox:
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Accept': 'application/json'
}
If I use double-quotes, then these headers are not transmitted to the server and XML is returned instead.
Ok, found the problem of why it's happening, but not the root cause.
I'm using the web api with asp.net mvc4 for the json service. It turns out somehow that for dojo the service is returning xml but for jQuery it returns json.
So, if it interests anyone else, how I fixed it, is that in WebApiConfig I removed xml as a supported return type:
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
Since I"m only interested in JSON, this is ok for me, but if you need to support both, then you may have to look deeper.
So, to summarize, the issue is not really a dojo xhr issue, i.e, not a client issue, it's a server issue not handling the request properly.
Hope it helps anybody else.