Tag Archives: AJAX

Trigger Basic Auth Dialog with jQuery / AJAX

05 May 2017

We’re all familiar with basic authentication (or should be) – my experience with it has been via cPanel or doing it by hand on *nix servers. Once setup it just works. The other day I was integrating an app into a service where the dev environment had basic authentication on it. My AJAX calls were blocked (naturally) but did not trigger a username/password dialog to appear. I had assumed that the browser would just “do its thing”.

What is happening behind the scenes is that my AJAX call causes the server to return a 401 HTML error page. This is an unexpected response that jQuery can’t handle and that will cause the following error in the console:

$ Uncaught SyntaxError: Unexpected token < in JSON at position 0 at JSON.parse ()

jQuery will also return a status code “0” which, by the way, is a generic error from jQuery. As the response from the server was an HTML document (401 error page) jQuery couldn’t parse it (it was expecting the response to be JSON) thus the above error. Lacking any proper status code to use jQuery then just uses “0”.

Lastly if I inspect the response header I can see that WWW-Authenticate: Basic appears. That’s a clue as to what we should do to get things working which is to add a Authorization:Basic header to our AJAX request to begin with.

We can add the necessary header by specifying the beforeSend callback when we configure the AJAX request. Inside of the callback we can create the Authorization header that will be added to our request. See the following example:

  $.ajax(
    {
      method: 'POST',
      contentType: 'application/json',
      url: 'service URL here'
      data:'data here',
      beforeSend: function (xhr) {
        xhr.setRequestHeader ('Authorization', 'Basic xxxx');
      },
    })
    .done(function( data, textStatus, jqXHR ) {
      // do something here...
    })
    .fail(function( jqXHR, textStatus, errMsg ){
      // do something here...
    });

Here you can see that we are setting the “Authorization” header via xhr.setRequestHeader. The spec says that Basic should be followed by a base-64 representation of the user name and password to authenticate with but in this case we are using an arbitrary string. Since its obviously wrong the server will respond by asking for the correct credentials; the authentication dialog will appear.

As you can see there is some interaction going back and forth between the client and the server. If you’re attentive to the network tab in the Chrome console you can see the handshaking as it happens.

Mixing jQuery and reCaptcha in Forms

06 Oct 2013

The business of collecting user data includes the ubiquitous form. The thing with forms is that they are the first to see abuse on the Internet and if left unprotected your inbox or database will soon be overrun with spam. One of many methods of protecting forms is the CAPTCHA. CAPTCHAs require that a user interpret a randomly-generated image by typing its value into a text field. Since automated programs (bots) can’t read the image they are stopped cold. Humans and their famously short attention spans happen to have enough bandwidth to tolerate a CAPTCHA or two. The Spammer variants, on the other hand, seem to lack the patience needed and will quickly move on to easier pickings of which there are untold thousands. So then, while a CAPTCHA is a minor inconvenience to your end-users it’s presence more than makes up for itself by its ability to completely stave off an avalanche of useless form posts.

Google provides a CAPTCHA service called reCAPTCHA which is the subject of this article.

The workflow I’ll be implementing is the following:

  1. User “submits” form
  2. The form is validated
  3. If form validation succeeds I then make an AJAX call to the reCaptcha service via a proxy to see if the user entered the correct reCaptcha value
  4. If an incorrect value was entered I’ll display an in-line message to the user
  5. If the correct value was entered I will submit the form

You can see this process in action below:

Register for a set of reCAPTCHA keys

You must first sign up to use reCAPTCHA by visiting http://www.google.com/recaptcha. After you register click the “Add Site” link and add your site. After you add a site you will get 2 keys – keep these handy, we’ll need them later.

Download the reCAPTCHA PHP Library

You will also need to download the reCAPTCHA PHP Library (I’m assuming that your site is on a PHP-compatible server).

Setting up a proxy

Since we plan on making AJAX calls to the reCAPTCHA service we know we will need a proxy as we would otherwise run afoul of the browser’s cross-domain policy. The way we will circumvent this is by creating a proxy. This proxy will handle communication between our web page and reCAPTCHA by forwarding our submitted form data to the reCAPTCHA service which in return responds to the proxy and then the proxy hands the response back to our web page.

The reCAPTCHA PHP library contains everything we need to setup our proxy. The library contains 5 files – we will be using 2 of them:

  • recaptchalib.php
  • example-captcha.php

The second file – example-captcha.php – will need to be modified for our purposes. Here is the original file (this is version 1.11) before any changes:


  
    
is_valid) { echo "You got it!"; } else { # set the error code so that we can display it $error = $resp->error; } } echo recaptcha_get_html($publickey, $error); ?>

To get to where we need to be we need to remove all html and make a couple of tiny changes to the PHP. I won’t walk through them in detail opting instead to just show you the finished edited file (the savvy among you will no doubt notice the differences) and to mention that the public and private reCAPTCHA keys are in use here:

is_valid) {
        echo "success";
    } else {
        echo "failure";
    }
}
?>

The line that echoes “success” is what we will be listening for in our AJAX call to determine if the reCAPTCHA verification was successful.

At this point your proxy is done. Go ahead and place your modified example-captcha.php and the unchanged recaptchalib.php on your server in the same folder as your form.

Add the jQuery and reCAPTCHA JS Libraries

You need to add these two lines within the head of your document (use whatever version of jQuery your project requires):

...


...

Setting up your form

The form code below is pretty basic – things to pay attention to:

  • This is a template for the reCAPTCHA functionality only – you still need to configure your form to work with your form remailer (i.e., gdform.php on GoDaddy, formmail.php, cgiemail or whatever the case might be)
  • Note the onsubmit=”return doForm()” in the FORM tag – this is the hook to our JavaScript that communicates to the reCAPTCHA server
  • There are 2 divs present:

    • <div id=”recap”></div> this is the wrapper for the reCaptcha itself
    • <div id=”err”>…</div> This is the in-line error message that we will display if the reCAPTCHA verification fails.
       
  • Note the style tag – we have a css class called “hidden” that is assigned to the reCAPTCHA error div. If there is an error we use jQuery to remove the class and show the error message to the user
     
...



Name:
...

Inserting the reCAPTCHA, validating Form and reCAPTCHA input

Next we need to insert the reCAPTCHA elements into the document. In the code that follows you can see that I’m inserting the reCAPTCHA on jQuery’s document.ready event.

When the form is submitted I first validate the form input which you can see in the doForm() function. If validation passes I then attempt to validate the reCAPTCHA via the recapVerify function.

Its all put together in the code snippet below (** add your public key where indicated in line 41 **):

...

...

And that should do it. Download all files here.

Cache Busting Your Web Service Requests

29 Jun 2012

While working with web services you always need to keep in mind that web browsers cache files. if you web service request doesn’t change ever so slightly you will run into the issue of the web browser not pulling the new response but instead pulling the previously cached response. This is easily mitigated by adding a variable that itself is always unique – notice that i didn’t say “random” – random may work, sure, but “random” means that you run the risk of encountering that number again at some point. Yes, feel free to come up with a random 20 digit number and it may be for all intents and purposes appear to be “unique” but the risk of that number re-appearing is still there, however obscure it may be. As most web service calls are GET requests its as simple as adding a new name/value pair with a unique value to every request. The service ignores it and the browser takes note that the request is different than the previous request and so accepts the new response from the server.

Add the following somewhere within your code to get the unique value:

...
   var d = new Date();
   var unique = d.getTime();
...

That gives you a number similar to 1340979406482. That value is the number of milliseconds since January 1, 1970 so naturally it increments every millisecond. Ideally the getTime() method would accept a date as an argument and would then provide the milliseconds between Jan 1, 1970 and the specified date but since we don’t provide that value the current date is assumed. So, that number represents the number of milliseconds from that date in 1970 and the millisecond in time when the code was executed.

I have seen people blog this topic but include dividing the millisecond value by 1000 and rounding the result. Not a great idea. Dividing by 1000 and rounding the result shortens the length of the number by 3 digits. If you shorten it too much it won’t be useful. Already, by dividing by 1000 I’m not getting a number that updates every millisecond but instead a number that updates every second. I suppose it depends on your idea of “unique” and your specific application, but I’d rather have the guarantee of uniqueness than have something that is fuzzy like doing Math on the already guaranteed unique number… makes no sense.

As to applying this, here’s a jQuery example:

...
var d = new Date();
var unique = d.getTime();
var dataStr = 'name_value_pairs_here';
$.ajax({
  url:      	'/some_service_here/',
  data:      	dataStr + '&nocache=' + unique,
  contentType:	'application/x-www-form-urlencoded',
  dataType: 	'json',
  error:function(obj,status,xhr){
    // handle error here
  },
  success:function(obj,status,xhr){
    // handle response here
  }
});
...

And better yet – jQuery has such a thing built into it, simply set the cache attribute as in this example:

...
var dataStr = 'name_value_pairs_here';
$.ajax({
  url:      	'/some_service_here/',
  data:      	dataStr,
  cache:        false, // cache buster
  contentType:	'application/x-www-form-urlencoded',
  dataType: 	'json',
  error:function(obj,status,xhr){
    // handle error here
  },
  success:function(obj,status,xhr){
    // handle response here
  }
});
...

When using the “cache” attribute within the jQuery Ajax config object jQuery will append a new name/value pair to the GET request in the form of:

  1. _=[timestamp]

Where “[timestamp]” is a unique value.

The usefullness of using d.getTime() is still there outside of jQuery. For example any call to a file that you don’t want to be cached, such as web pages, JS files, CSS, etc.

Test Cross Domain Ajax In Chrome

01 Jun 2012

If you are like myself and leave the server-side stuff to those who like doing that type thing (well, I dabble here and there) then you love to find ways to avoid asking them to do stuff for. In the world of HTML 5 mobile application development you are always integrating with some service and often its cross-domain. If for some reason your cross-domain calls are not using JSONP but perhaps regular JSON or SOAP/XML you will immediately run into problems testing your mobile application within Chrome.

Chrome is really where you want to do your development as it takes too much time to compile an app and load onto a device just so you can test though yes, you do ultimately want to test on-device. WEINRE takes some of the pain out but it still has a mild sting to it. Anyway you can still use Chrome for your cross-domain non JSONP requests. Just start it up with a switch to disable web security – the switch is:

–disable-web-security

What I do is have two shortcuts on my desktop – a normal one for Chrome in all of its default glory, and another one specifically for development that will launch Chrome with its web security feature disabled.

So how does one go about using this handy switch/feature? First, create a shortcut on your desktop to Chrome. Don’t know how to do that? Well my friend, thats what Google is for. Next, make a copy of the shortcut – rename it to something obvious, for example “Chrome Security Disabled” or similar.

Next right-click and choose properties. You should see something like this:

Next, note the field that is hilited – the one labeled “Target”. That’s the path to the Chrome executable. type a space after the exe and paste in the switch as seen below:

Hit “Apply”, then “OK”. Thats it!

There are many more switches that you can use, they are documented at the Google Chrome Repository.

Don’t forget that you have to make sure you kill all chrome instances first, or the command line switches won’t have any effect. In VISTA if you have an instance of Chrome open and try to edit the target of a shortcut the edit won’t take. Again, close all Chrome instances first.

Also don’t’ forget that you have security disabled! Its easy to think everything works fine in Chrome when it won’t in the real world and can be a source of frustration when you wonder why your app works on your computer but not when deployed to a server. Another impact of forgetting that you have lowered your security is browsing the Internet in general – you will need to completely shutdown Chrome and then start a “normal” Chrome instance to regain previously disabled security features.

Cross-Domain Ajax and XML with jQuery

07 May 2012

Did a fun little thing today – built a jQuery/PHP-based Cost of Living (COL) calculator for a city’s website (sorry, have to be vague on the client’s name) utilizing the data from www.coli.org.

Coli.org provides a service that allows interested parties to compare the cost of living across a range of criteria between two different locations within the Untied States.

Typically as in this case the destination location is the city that is providing the calculator. The intent is to allow potential new residents to compare their current cost of living to the destination city.

To start with you will need to query two of the services on page load – one to get the list of origin locations and another to get the list of destination locations (typically one or two locations – and if you want only one destination you could easily hard code the value of the city via a hidden form field or similar). Once you receive this data you will need to populate two select lists to allow the user to make their selections. With that data you will then query another web service to get the results. Further manipulation of the returned data on the client side with some math will get you percentages and adjusted income.

Approach

There are a couple of ways to approach this – server-side or client-side. As I’m a front-end guy my approach then was to do Ajax knowing that jQuery makes it trivial to do AJAX and parse XML. However, since this was going to be a cross-domain call a 100% client-side solution wouldn’t be possible. Instead, I would have to use something that wouldn’t be subject to a browser’s cross-domain policy – a proxy to act as the go-between for client and the web service. The server the site is hosted on supports PHP and so that dictated the tech to use. A little research revealed PHP’s cURL and a few lines of code later I had myself the proxy that I needed to accomplish the cross-domain service calls.

Proxy

One thing I noticed in the live examples that Coli.org provided is that the GUID was exposed which seemed unnecessary to me. So, instead of following their implementation examples verbatim I placed the GUID into the PHP proxy thereby keeping it secure. Of course, Coli.org might be mitigating GUID abuse by restricting calls to registered domains – I’ve no idea, but in any event, it seemed to be a better approach to not expose it if possible.

If you’re looking into using the Coli.org data by mirroring my approach you’ll be interested in the proxy, which I’ve provided below:

...

define ('HOSTNAME', 'http://www.coli.org/_clicktocomparews/service.asmx/');
$path = $_GET['ws_path'];
$url = HOSTNAME.$path;
$session = curl_init($url);
if ($_GET['ws_path']) {
     $getvars = '';
     while ($element = current($_GET)) {
          $getvars .= key($_GET).'='.$element.'&';
          next($_GET);
     }
     $getvars .= '&licenseeGUID={_YOUR_GUID_GOES_HERE_}';
     curl_setopt ($session, CURLOPT_POST, true);
     curl_setopt ($session, CURLOPT_POSTFIELDS, $getvars);
}

curl_setopt($session, CURLOPT_HEADER, false);
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
$xml = curl_exec($session);
header("Content-Type: text/xml");
echo $xml;
curl_close($session)

...

All you need to do is to replace the string “_YOUR_GUID_GOES_HERE_” with the GUID that Coli.org gives you and as long as your server supports cURL your proxy is ready to be used. Note that the curly braces surrounding the numeric GUID is necessary.

AJAX & jQuery

Next is the AJAX. jQuery really makes it easy to do AJAX, here’s a stripped down version of my AJAX call to the Proxy:

...
function doAjax(wsPath,args){
   var dataStr = args ? 'ws_path=' + wsPath + '&' + args : 'ws_path=' + wsPath;
   $.ajax({
      url:      '/col_proxy.php',
      data:      dataStr + '&action=compute',
      dataType: 'xml',
      error:     function(xhr,status,err){
         //console.log(status + '\n' + err);
      },
      success:function(responseData,status,xhr){
         // console.log('success')
      });
}
...

So lets break this down, doAjax() expects two arguments to be passed to it. “wsPath” is the web service path, “args” are the arguments to be sent to the webservice. You would use the success callback to process the returned XML.

The web service paths for Coli.org’s web services are the following (as can be publicly seen here):

  • GetComparisonDetail
  • GetComparisonSummary
  • GetFromCommonPlaceTotal
  • GetFromLocations
  • GetPeriodInfo
  • GetSampleLocations
  • GetToCommonPlaceTotal
  • GetToLocations

Since I need the list of origin and destination locations first before any other web service can be used I call doAjax() via $(document).ready with the following placed at the end of my script:

...
$(document).ready(function(){
... 
... 
  // bottom of script
  (function init(){
    doAjax('GetFromLocations',null);
    doAjax('GetToLocations',null);
  })();
}); 

The “init” function is self-invoking and as you might have guessed, “GetFromLocations” is the web service for getting the list of origin locations, and “GetToLocations” provides the list of possible destination locations. These two services don’t require any extra attributes so the second argument to doAjax() is simply passed null.

The next task would be to call another webservice once the origin and destination cities have been selected by passing the data that repesents the city selections and the desired web service path. I didn’t use all of the webservices that Coli.org has availiable as they weren’t needed for my application. For my needs only two more calls were needed: “GetComparisonDetail” and “GetComparisonSummary”. In both of these cases the required name-value pairs to send along are:

  • fromCity
  • toCity

So then, knowing this and we would would pass the web service name as the first argument for doAjax() and construct the name/value pair string to be the value of the second argument. Something that in your own application may look similar to this:

...
// put together the "from" and to" name value pairs
// where "fromVal" is the origin city code and
// "toVal" is the destination city code
var args = 'fromCity=' + fromVal + '&toCity=' + toVal;

// specify the web service to use
var wServiceName = 'GetComparisonSummary';

// query the webservice
doAjax(wServiceName,args);
...

Processing XML

The result from a successful web service call will be XML. Coli.org unfortunately doesn’t provide XML samples so you’ll have to discover this on your own. What I did was to construct the entire web service call **sans proxy** directly in my browser’s address bar. The entire call, from www.colie.org… all the way to the GUID and any other necessary arguments – and then hit enter on my keyboard. If succesfull the XML response will appear in-browser.

Here’s an example of discovering the XML structure via a direct link in a browser:

http://www.coli.org/_clicktocomparews/service.asmx/GetFromLocations?licenseeGUID={_YOUR_GUID_HERE}

Here is a portion of the returned XML:

...

  
  T-Bone SteakFairbanksAK110.439.2655586592178789Q12011
T-Bone SteakWarsawIN19.79.2655586592178789Q12011
Ground BeefFairbanksAK13.83.0240502793296091Q12011
...

Once you know the XML structure the next few steps couldn’t be easier – in this case, each location is described as an XML node/tag called “Table”. Within this node are other nodes that themselves contain the specific values that you are looking for, such as:

  • Category_Name
  • Place_Name
  • State
  • Cost

In jQuery to find any node/tag within an XML doc simply use the “find()” method and you will get an array of all matching nodes. looking back at the doAjax() sample code we can see that the success callback assigns the returned XML to “responseData”. So then we have all the piecess to this rather small puzzle. To find all of the “Table” nodes within “responseData” our jQuery code would be:

...
var tableArray = $(responseData).find('Table');
...

This gives us all the “Table” nodes – but… we of course have to loop through each one looking for the specific values that we need and while a for loop would work here to iterate through each “Table” we should instead utilize chaining and jQuery’s built-in iterator, the “each()” method, and its callback:

...
$(responseData).find('Table').each(function(){
  // additional processing instructions here;
});
...

Pretty cool how chaining allows us to do multiple things simultaneously, right? This is a rather small chaining example too, but anyway, the next step is to find the desired values within each individual “Table” node. This is quite simple as well, see the next example:

...
$(responseData).find('Table').each(function(){
  var cname = $(this).find('Category_Name').text();
  var pname = $(this).find('Place_Name').text();
});
...

The $(this) statement in this context simply means “the current Table node” – then we look for the specific child node inside the current Table by again using the find() method. And on the end, we use the “text()” method to pull the text that is within the desired nodes. Here we are pulling the text for the “Category_Name” and “Place_Name” nodes which again are child nodes of “Table”.

THis is great, but this code doesn’t do us much good at this point as all we end up with are the Category and Place values of the very last Table in two variables. Instead we would actualy use this to populate the page with HTML for each individual Table. We can quickly print out the results to the page by appending html to a pre-existing div. As seen in the following example our existing div is called “tableResults”:

...
$(responseData).find('Table').each(function(){
  var currentRow =  '

Category: ' + $(this).find('Category_Name').text(); currentRow += ', Location: ' +$(this).find('Place_Name').text() + '

'; $('#tableResults').append(currentRow) }); ...

This will print out the Category and Location of each Table node within the mentioned pre-existing div called “tableResults”. Note that I’ve wrapped each set of Table data in a P tag. This gives us some automatic padding between lines which makes things a little more visually appealing. This sample is pretty basic, you’ll of course want to do more in your own application.

And… (drum roll)… thats about it. This was just a brief overview of the technical aspects of integrating into Coli.org’s web services via client-side technologies, not a complete functional example though with the code samples above – and complete working PHP-based proxy – you should be able to integrate with their web services quite easily or at the very least get a jump start on a similar project of your own.