I run a REST-API build on top of Sinatra.
Now I want to write a jQuery Script that fetches data from the API.
Sinatra is told to response with JSON
before do
content_type :json
end
A simple Route looks like
get '/posts' do
Post.find.to_json
end
My jQuery script is a simple ajax-call
$.ajax({
type: 'get',
url: 'http://api.com/posts',
dataType: 'json',
success: function(data) {
// do something
}
})
Actually everything works fine as long as both runs on the same IP, API and requesting JS.
I already tried to play around with JSONP for Rack without any positive results, though. Probably I just need a hint how to proceed.
Use JSONP (JSON with padding). There is a JSONP extension for Rack.
Basically, you'll call:
$.ajax({
type: 'get',
url: 'http://api.com/posts',
dataType: 'jsonp',
success: function(data) {
// do something
}
})
which translates to a request like:
http://api.com/posts?callback=someJSFunc
and your server will respond, e.g.:
someJSFunc({"json":"obj"});
Of course, clients can do JSONP requests without jQuery. The trick with JSONP is you serve scripts, which can be cross-domain, rather than pure JSON, with cannot.
Thank's for the answers so far.
You were right and jsonp would solve the problem. The code snippets for javascript work fine.
To set up Sinatra is very easy as it is build on top of Rack.
Therefore simply install the rack-contrib gem
gem install rack-rack-contrib --source=http://gems.github.com/
(or put it in your Gemfile) and add
require 'rack/contrib/jsonp'
use Rack::JSONP
to your application.
This middleware provides regular JSON to non-JSONP clients and JSONP to jQuery & co.
It might be interesting to you http://github.com/shtirlic/sinatra-jsonp — this extension adds missing functionality to sinatra
Also available as gem gem install sinatra-jsonp
Try to call
$.getJSON("http://example.com/?callback=?",function(data) { alert(data); });
In this sample main keyword is construction "callback=?", so you need to process this param in your server-side script, and make a valid JSONP, like this:
function({ "foo" : "bar" });
Where "function" is random data, which is generated by jQuery automatically. Read more here about jQuery and cross-domain JSONP.
Related
I am finding that GoogleBot is crawling webservice URLs which are referenced in JavaScript/AJAX code. The URL is already in robots.txt as an exclusion, but Google no longer seems to obey robots.txt when determining what to crawl - it only seems to use it to know what not to index.
Thankfully these service URLs only return data rather than performing actions but it's messing up the statistics we collect which is highly undesirable. I cannot personally see how Google is even finding out the URL of the webservice unless it crawls arbitrary strings in Javascript code (which seems unlikely?).
For some URLs this also results in me getting LOTS of Elmah error messages from the website which say:
System.InvalidOperationException: Request format is unrecognized for URL unexpectedly ending in '/GetShortlists'." ... as Google tries to GET the URL when it only supports POST.
The code it's finding the URLs in is as follows:
function GetShortlistsForUser() {
$.ajax({
type: "POST", url: "/WebService/WebService.asmx/GetShortlists",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) { /*--CUT--*/ });
}
});
So should I obfuscate the URL somehow by perhaps replacing the slashes, or is there a better way to stop these getting crawled?
(1) Try break the url format in your javascript codes, e.g,
var breaker="x/G";
......
url: "/WebServic"+"e/WebService."+"asm"+breaker+"etshortlists",
since Google may use regex to determine which part is url... (I am not sure if this could prevent crawlers, but if it works, you don't need to break it to this extend as it also breaks code reading experience.)
(2) On your server, Google crawler typically use customized agent string, so you can deny it (or ignore it).
I am using a JSON API plugin for wordpress to allow me to work with the sites content in a phonegap application I'm building.
However due to the complexity of some of the content on the site (caused by shortcodes outputting graphs, sliders etc..) these aren't suitable to be displayed in the mobile app. I need to remove the shortcodes from the JSON output.
I have found that I can hook into the_content filter in wordpress and use remove_shortcode to take out the necessary shortcodes. But the problem is I can only do this when I access the json url via my browser.
For example, I may use http://example.com?json=1 to return recent posts. If I type this in my url bar I can parse the url, determine that json=1 is there and strip the shortcodes.
However when I am doing an ajax (JSONP) request from my mobile application, it doesn't appear to be able to check the url for the json parameter, thus my shortcodes are not being stripped. I can't even pass in any headers either as they won't make it because of the nature of JSONP requests I believe.
Has anyone got any ideas as to how I can figure out when a JSON request from my mobile application is received, so that I can then remove the shortcodes?
Something like
if(is_json()){
//remove shortcodes
}
And before it's brought up, I have asked this on the Wordpress Stackexchange but to no avail
Update:
Here is the code I use for the ajax request from the mobile app
$.ajax({
url: "http://www.example.com/?json=1",
dataType: "jsonp",
async: true,
success: function(result) {
app.populate(result)
},
error: function(request, error) {
alert('Network error has occurred please try again!');
}
});
Prompted by one of the comments, I found what I needed in the JSON-API plugin files.
If you look in json-api/models/post.php there's a function set_content_value() which shows where the plugin is pulling in the content. Here you can modify it as needed, in my case I used it to remove certain shortcodes with the Wordpress remove_shortcode() function
Can't you just use the remove_shortcode function anytime your plugin serves content to a client?
Could you also give us the name / url of your plugin?
Maybe a bit of code woudln't hurt either. Would you mind giving use your phonegap application's API request code snippet?
Thanks.
I have a problem with my Ajax Request I want to send to a specific page. I know that I can't just send Ajax requests to different pages because of the cross-domain problem. So I have chosen the jsonp method to do that.
My code is:
exs = function(url){
$.ajax({
type: "GET",
dataType: 'jsonp',
jsonp: "callback",
url: "http://example/api.php?callback=?",
success: function(response) {
console.log(response);
}
});
}
So what this returns is the following:
"Uncaught SyntaxError: Unexpected end of input"
Does anyone know what's the problem?
I have checked the page of the API I'm sending the request, there I see just plain HTML.
And I want to save that HTML output to a variable.
I haven't found a solution yet. Any ideas?
I know that I can't just send Ajax requests to different pages because of the cross-domain problem. So I have chosen the jsonp method to do that.
If you want to use JSONP then the server has to provide a JSONP response, not an HTML response.
You can't bypass the same origin policy without either the cooperation of the server or the use of a proxy.
If you were using JSONP, then you should specify dataType: "jsonp" not dataType: "json" and you should generally avoid specifying the name of the function using jsonp: "callback" in favour of letting jQuery generate it from the success argument.
I'm trying to receive data from SendGrid API
$.ajax({
type:'GET',
url:"https://sendgrid.com/api/bounces.get.json",
data: {api_user:'username',api_key:'userkey',date:1},
success: function(data){
console.log(data)
},
crossDomain: true,
dataType: 'jsonp',
error:function(a,b,c){
console.log(a);
}
});
Console shows:
Object { readyState=4, status=200, statusText="success"}
parsererror
Error: jQuery17208301184673423685_1374648217666 was not called
Where is the bug or issue ?
The issue is that SendGrid does not support jsonp.
Unfortunately, switching to plain JSON will not work either, as SendGrid has no CORS headers and browsers will not allow you to access the pages. In short you cannot make AJAX requests dorectly to SendGrid.
However, generally this is for the better as all SendGrid endpoints require authentication and having your username and password in an AJAX request would allow users to take them and then use them to send email.
To get these stats on the frontend, you'll need a server to get them and output them on your domain or a domain with CORS allowances.
Here comes a one click solution!
Deploy your instance of SendGrid Proxy to Heroku
Use {your-sendgrid-proxy}.herokuapp.com instead of api.sendgrid.com
Done (Really)
How it works:
It creates a node powered http proxy using express-http-proxy
It adds needed headers such as Authorization and Content-Type
It overrides Access-Control-Allow-Origin to * to make your browser CORS warning free
See how the magic is working. Feedback is welcome!
I'm trying to submit a form with a file field in it via jQuery.Form plugin, here's the code:
$('form').ajaxSubmit({
url: "/path",
dataType: "json",
contentType: "multipart/form-data"
...
The server then returns json as a response. Works great in all browsers except IE, which tries to download the response as a file. If I remove the file field from the form, it also works just fine.
I've seen various solutions here and in Google and basically tried almost everything described, including setting enctype for the form via jQuery, but it didn't work.
Any suggestions would be very welcomed.
You can simply return JSON from the controller as "text/html" and then parse it on the client side using JQuery.parseJSON().
Controller:
return this.Json(
new
{
prop1 = 5,
prop2 = 10
},
"text/html");
Client side:
jsonResponse = $.parseJSON(response);
if(jsonResponse.prop1==5) {
...
}
This solution has been working for me.
I have not found a direct solution to this, but I eventually implemented the following workaround: I used dataType: "text" in my ajax settings and then returned plaintext from controller, separating values with ; and parsing them on the client side. That way IE and Forefox stopped trying to download a response.
I did not find any other way to prevent said behavior other then to return plaintext. I tried returning JSON as plaintext and then parsing it with $.parseJSON, but it didn't work due to some js errors.
Just send response with 'Content-Type', 'text/html' header.
Just set Content-Type: text/html
This happens because IE8 doesn't recognize application/... mimetype.
This works for me.
Hope it helps.
Same situation than you folks : the problem only occurs with enctype="multipart/form-data" form used with $(form).ajaxSubmit(...) function.
My team and I had to replace (in this function) dataType: 'json' option with dataType: 'text' and add responseText = $.parseJSON(responseText); to force server response parsing.
Of course we also had to step in server side to return a response with "text/plain" header instead of "application/json"
We're not proud of it :( IE is definitely killing everything...
I didn't try the advice given by zmonteca (already spent too much time on it) but it seems worthy : let us know if it was OK for you.
Hope it helps!
if you work with Zend you can do
$this->getResponse()->setHeader('Content-Type', 'text/html');
in your controller action. and on client-side, in case of jQuery, you can do
data = $.parseJSON(data);
This site has some info about wrapping the response in a
http://forum.jquery.com/topic/jquery-form-malsup-ie7-file-download-security-warning-on-ajax-file-upload
I seemed to be able to fix my problem by making my server return the JSON as a string.
Then I used JSON.parse() inside the complete event.
I came up with the following workaround (in Zend Framework):
if (!$this->_request->isXmlHttpRequest()) {
die('<textarea>'.Zend_Json::encode($data).'</textarea>');
}
$this->view->assign($data);
Removing ContentType from serverside works for me.