Web Services Fundamentals: Difference between revisions

From NSB App Studio
Jump to navigation Jump to search
 
(23 intermediate revisions by 2 users not shown)
Line 13: Line 13:
= Same Origin Policy and CORS =
= Same Origin Policy and CORS =


'''Same Origin Policy (SOP)''': The policy permits scripts running on pages originating from the same site – a combination of scheme, hostname, and port number – to access each other's DOM with no specific restrictions, but prevents access to DOM on different sites.
'''[http://en.wikipedia.org/wiki/Same-origin_policy Same Origin Policy (SOP)]''': The policy permits scripts running on pages originating from the same site – a combination of scheme, hostname, and port number – to access each other's DOM with no specific restrictions, but prevents access to DOM on different sites.


'''Cross Origin Resource Sharing (CORS)''': is a mechanism that allows scripts on a web page to make AJAX requests to another domain, not the domain the script originated from. Such "cross-domain" requests would otherwise be forbidden by web browsers, per the Same Origin Policy.  
'''[http://en.wikipedia.org/wiki/Cross-origin_resource_sharing Cross Origin Resource Sharing (CORS)]''': is a mechanism that allows scripts on a web page to make AJAX requests to another domain, not the domain the script originated from. Such "cross-domain" requests would otherwise be forbidden by web browsers, per the Same Origin Policy.  


* Suppose we create an AppStudio app.
* Suppose we create an AppStudio app.


* It gets saved on our server (nsbapp.com), together with all the files it needs to run.
* It gets saved on the AppStudio Server, together with all the files it needs to run.


* When someone runs it, they enter http://www.nsbapp.com/HelloWorld into their browser.
* When someone runs it, they enter http://www.nsbapp.com/HelloWorld into their browser.
Line 25: Line 25:
* The app is then loaded from the website and stored on the device.
* The app is then loaded from the website and stored on the device.


* Since the app is loaded from nsbapp.com, SOP allows it to access resources on nsbapp.com: HTML, JavaScript, CSS files, images, etc.
* Since the app is loaded from the AppStudio Server, SOP allows it to access resources on the AppStudio Server: HTML, JavaScript, CSS files, images, etc.


* However, it would not be allowed full use of resources on another site, such as nsbasic.com.
* However, it would not be allowed full use of resources on another site, such as myserver.com.


* CORS is a way of allowing apps running from another server to access specific resources on the server.
* CORS is a way of allowing apps running from another server to access specific resources on the server.
<div class="page-break"></div>


= AJAX =
= AJAX =


'''AJAX''': stands for Asynchronous JavaScript and XML. It is a group of interrelated web development techniques used on the client-side to create asynchronous web applications.   
'''[http://en.wikipedia.org/wiki/Ajax_(programming) AJAX]''': stands for Asynchronous JavaScript and XML. It is a group of interrelated web development techniques used on the client-side to create asynchronous web applications.   


* It has evolved since it was originally named.
* It has evolved since it was originally named.
Line 39: Line 41:
* Now, it does not necessary involve asynchronous, JavaScript or XML!
* Now, it does not necessary involve asynchronous, JavaScript or XML!


* The AppStudio AJAX statement allows an app to request information from a web service.
* The AppStudio [[Ajax]] function allows an app to request information from a web service.


* It is based on the XMLHttpPost function in JavaScript.
* It is based on the [http://www.w3schools.com/ajax/ajax_xmlhttprequest_send.asp XMLHttpPost] function in JavaScript.


<div class="page-break"></div>
=== A Simple Exchange of Data with the server ===
=== A Simple Exchange of Data with the server ===


Line 49: Line 52:
[[File:Ajax1.png]]<br />
[[File:Ajax1.png]]<br />


The only code in this app is the "Reverse" button. The [[Ajax]] function sends the contents of the top TextArea to a PHP script that is running on the server. If it returns successfully, we display what came back. Otherwise, we show the error:
The only code in this app is the "Reverse" button. The [[Ajax]] function sends the contents of the top TextArea to a [http://en.wikipedia.org/wiki/PHP PHP] script that is running on the server. If it returns successfully, we display what came back. Otherwise, we show the error:
<pre>
<pre>
Dim req
Dim req
Line 72: Line 75:
Here is the result:
Here is the result:


[[File:Ajax2.png]]
[[File:Ajax2.jpg]]


* The php script needs to be on the same folder on the server as the AppStudio app.
* The php script needs to be on the same folder on the server as the AppStudio app.
* It can be uploaded with the app.
* It can be uploaded with the app.
* This is equivalent to entering the following URL into a browser:
https://www.nsbasic.com/i/Ajax/ajax.php/?myText=%22NSB/AppStudio%20makes%20Ajax%20easy!%22
<div class="page-break"></div>
=== Cross Origin Attacks! ===
What happens if we run this same example in our local browser, by just choosing Start in Desktop Browser under the Run menu?
[[File:Ajax3.png]]
* We get a cross origin request error.
* The traceback shows it is caused by our Ajax call.
* When we run in a local browser, the origin of the app is our local machine.
* So the browser protests when we try to run a PHP script on another machine.
<div class="page-break"></div>
=== Using POST to Send more Data to the Server and save it ===
Let's extend what we are doing a bit and talk about using the POST method.
We discussed the simplest [[Ajax]] call, which sends data to the server by adding it to the end of the URL, a method called, rather misleadingly, GET. But what if we want to send more data? GET has a limit, some say, of around 2000 characters. For more than that, we'll use the also badly named POST method. POST has an upload limit on most servers of 8 megabytes. If you need more, server settings can be adjusted.
Let's look at some code. You'll see it looks very much like our last post:
<pre>
Function btnAjax_onclick()
  req=Ajax("ajaxPost.php","POST",txtSend.value)
  If req.status=200 Then 'success
    htmResponse.innerHTML=req.responseText
  Else 'failure
    htmResponse.innerHTML="Error: " & req.err
  End If
End Function
</pre>
The difference is a couple of extra parameters. We add "POST" and the data we want to send as a separate parameter. Before we talk about what is going to happen at the server end, let's see what the app looks like:
[[File:Ajaxpost.png]]<br />
<div class="page-break"></div>
* Here is the PHP code on the server which we are calling:
<pre>
<?php
// uncomment the next line to see runtime error messages from this script
// ini_set('display_errors','1');
// Get the data from the client.
$myText = file_get_contents('php://input');
// Send back the text, reversed
echo "Data received from Device (reversed):<br>" . strrev($myText);
//write the data out to a file on the server
//make sure permissions are all OK!
$myFile = "AjaxPost/ajaxPost.txt";
echo "<p>Writing data to " . getcwd() . $myFile;
$f = fopen($myFile, 'w') or die("can't open file");
fwrite($f, $myText);
fclose($f);
?>
</pre>
The file_get_contents('php://input') call gets the data, exactly as it was sent. We'll do two things with it: echo it back reversed and we will write it to a file on the server. The first part is easy: anything in an echo statement is sent back to our app:
<pre>
echo "Data received from Device (reversed):" . strrev($myText);
</pre>
The second part involves a bit more PHP, but is straightforward. It writes the data which was received to a file.
<pre>
$myFile = "AjaxPost/ajaxPost.txt";
echo "<p>Writing data to " . getcwd() . $myFile;
$f = fopen($myFile, 'w') or die("can't open file");
fwrite($f, $myText);
fclose($f);
</pre>
What would you use this feature for?
* Upload a [http://en.wikipedia.org/wiki/JSON JSON] copy of your database.
* Upload some pictures in [http://en.wikipedia.org/wiki/Base64 Base64] format.
* Create a .htm file which can be accessed as a web page.
* Lots more ideas!
A tip on debugging PHP scripts Since PHP scripts run on the server and not on your screen, you don't get to see the error messages. This can make debugging difficult. If you put this statement at the top of your PHP script, the error messages will be echoed to your app:
<pre>
ini_set('display_errors','1');
</pre>
The error messages come back as HTML formatted text. The best way to look at them is to assign them to the innerText property of an HTMLview control.
<div class="page-break"></div>
=== Getting Data from Another Site ===
One of the basic security features of the modern web is the [http://en.wikipedia.org/wiki/Same_origin_policy Same Origin Policy]. It states that a web app cannot pull up just any data from another site. This becomes a problem if you need data on someone else's site.
Fortunately, they left an easy workaround. While a web app isn't allowed to access the files on another site, a PHP script is. We'll get our PHP script to do the dirty work for us and return the results to our app. The technique we will use is often called [http://en.wikipedia.org/wiki/Web_scraping scraping].
Time to look at some code again. Here's the AppStudio part that calls the PHP script. It looks very much like the code in A Simple Exchange of Data with the server above. The main difference is that we're calling a different PHP script.
<pre>
Function btnGetFile_onclick()
  req=Ajax("ajaxGetURL.php/?urlToGet=" & txtURL.value)
  If req.status=200 Then 'success
    htmResponse.innerHTML=req.responseText
  Else 'failure
    htmResponse.innerHTML=req.err
  End If
  htmResponse.refresh()
End Function
</pre>
Before we talk about what is going to happen at the server end, let's see what the app looks like:
[[File:Ajaxgeturl.png]]<br />
And here is what the PHP script looks like:
<pre>
<?php
$ch = curl_init($_GET['urlToGet']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($ch);
curl_close($ch);
echo $data
?>
</pre>
Let's take apart this one line:
* $_GET('urlToGet') gets the parameter string that was attached to the URL in our AppStudio code.
* _file_get_contents get the contents of the file, in this case, the URL that was passed.
* echo sends the result back to our AppStudio program.
Pretty simple, isn't it?
(In this example, we're grabbing the robots.txt file from Microsoft's site, just to show we can get files from anywhere. Nearly all sites have a robots.txt file: it is used to guide search engines.)
There is a simpler way to do this, but it can run into security problems.
<pre>
<?php
echo file_get_contents($_GET['urlToGet']);
?>
</pre>
<div class="page-break"></div>
=== How fast is it? ===
If your app is going to communicate with your server while it is running, you've probably wondered how much your app will slow down when it has to wait for the server.
In this blog post, we're going to make a program to test this. We'll construct a little program which sends data to the server as many times as it can. The server will record the information in a log file. Here is what our app will do:
<pre>
  Do Until SysInfo(10) > limit
    req=Ajax("ajaxLog.php/?myText=" + Now)
    counter=counter+1
  Loop
</pre>
[[SysInfo]](10) is the current time in milliseconds. Limit is the time we want run to. You can run this test for up to about 5 seconds: after that, the system will think you are in a endless loop and shut you down.
On the server side, we need a PHP script to get the messages and write them out to disk. Here's the code:
<pre>
<?php
  // read and append to file
  $myFile = "AjaxLog/log.txt";
  $f = fopen($myFile, 'a') or die("can't open file");
  fwrite($f, $_GET['myText'] . Chr(13) . Chr(10));
  fclose($f);
?>
</pre>
Now, let's run it on a few different devices and see how many accesses we can do per second:
{| class="wikitable"
|-
| Desktop (Ethernet) || 2745.0
|-
| iPhone 5 (WiFi) || 16.75
|-
| iPhone 5 (LTE) || 13.0
|-
| iPhone 4 (WiFi) || 10.5
|-
| iPhone (3G) || 2.5
|-
| Nexus S (WiFi) || 5.0
|-
| Kindle Fire (WiFi) || 9.0
|}
It's obvious that the speed that really depends on what kind of connection you have to the web. A hard wire to your router gets the best time. WiFi is much slower, and 3G is slower again. No real surprise here.
The speeds shown here probably are not what you will see if you run the same test. There are a number of factors that will affect the speed:
* Type of data connection
* Load on the network
* Number of hops the data has to make to get to the server
* Load on the server
(You can try this sample yourself - it is called AjaxLog in the Samples folder.)

Latest revision as of 08:56, 27 August 2015

Introduction

  • Web Services are resources which are accessed over the web
  • AppStudio Apps can access Web Services
  • The information that is pulled from the web can make interesting apps
  • Data can be pulled from your own server or someone else's.
  • Mashups are apps which pull information from more than one source

Same Origin Policy and CORS

Same Origin Policy (SOP): The policy permits scripts running on pages originating from the same site – a combination of scheme, hostname, and port number – to access each other's DOM with no specific restrictions, but prevents access to DOM on different sites.

Cross Origin Resource Sharing (CORS): is a mechanism that allows scripts on a web page to make AJAX requests to another domain, not the domain the script originated from. Such "cross-domain" requests would otherwise be forbidden by web browsers, per the Same Origin Policy.

  • Suppose we create an AppStudio app.
  • It gets saved on the AppStudio Server, together with all the files it needs to run.
  • The app is then loaded from the website and stored on the device.
  • Since the app is loaded from the AppStudio Server, SOP allows it to access resources on the AppStudio Server: HTML, JavaScript, CSS files, images, etc.
  • However, it would not be allowed full use of resources on another site, such as myserver.com.
  • CORS is a way of allowing apps running from another server to access specific resources on the server.

AJAX

AJAX: stands for Asynchronous JavaScript and XML. It is a group of interrelated web development techniques used on the client-side to create asynchronous web applications.

  • It has evolved since it was originally named.
  • Now, it does not necessary involve asynchronous, JavaScript or XML!
  • The AppStudio Ajax function allows an app to request information from a web service.

A Simple Exchange of Data with the server

Let's look at some code. We will have our AppStudio app send the server a string, which the server will return reversed. Here is what the app looks like:


The only code in this app is the "Reverse" button. The Ajax function sends the contents of the top TextArea to a PHP script that is running on the server. If it returns successfully, we display what came back. Otherwise, we show the error:

Dim req
Function btnAjax_onclick()
  req=Ajax("ajax.php/?myText=" & txtSend.value)
  If req.status=200 Then 'success
    txtResponse.value=req.responseText
  Else 'failure
    txtResponse.value="Error: " & req.err.message
  End If
End Function

The PHP script is even easier. It gets the input that is named myText, reverses it, and uses the echo statement to send it back.

<?php
 // Get the data from the client. 
 $myText = $_GET['myText'];
 // Send back the text, reversed
 echo "Data received from Device (reversed): " . strrev($myText); 
?>

Here is the result:

  • The php script needs to be on the same folder on the server as the AppStudio app.
  • It can be uploaded with the app.
  • This is equivalent to entering the following URL into a browser:

https://www.nsbasic.com/i/Ajax/ajax.php/?myText=%22NSB/AppStudio%20makes%20Ajax%20easy!%22

Cross Origin Attacks!

What happens if we run this same example in our local browser, by just choosing Start in Desktop Browser under the Run menu?

  • We get a cross origin request error.
  • The traceback shows it is caused by our Ajax call.
  • When we run in a local browser, the origin of the app is our local machine.
  • So the browser protests when we try to run a PHP script on another machine.

Using POST to Send more Data to the Server and save it

Let's extend what we are doing a bit and talk about using the POST method.

We discussed the simplest Ajax call, which sends data to the server by adding it to the end of the URL, a method called, rather misleadingly, GET. But what if we want to send more data? GET has a limit, some say, of around 2000 characters. For more than that, we'll use the also badly named POST method. POST has an upload limit on most servers of 8 megabytes. If you need more, server settings can be adjusted.

Let's look at some code. You'll see it looks very much like our last post:

Function btnAjax_onclick()
  req=Ajax("ajaxPost.php","POST",txtSend.value)
  If req.status=200 Then 'success
    htmResponse.innerHTML=req.responseText
  Else 'failure
    htmResponse.innerHTML="Error: " & req.err
  End If
End Function

The difference is a couple of extra parameters. We add "POST" and the data we want to send as a separate parameter. Before we talk about what is going to happen at the server end, let's see what the app looks like:


  • Here is the PHP code on the server which we are calling:
<?php
 // uncomment the next line to see runtime error messages from this script
 // ini_set('display_errors','1');
 
 // Get the data from the client.
 $myText = file_get_contents('php://input');
 // Send back the text, reversed
 echo "Data received from Device (reversed):<br>" . strrev($myText); 
 
 //write the data out to a file on the server
 //make sure permissions are all OK!
 $myFile = "AjaxPost/ajaxPost.txt";
 echo "<p>Writing data to " . getcwd() . $myFile;
 $f = fopen($myFile, 'w') or die("can't open file");
 fwrite($f, $myText);
 fclose($f);
?>

The file_get_contents('php://input') call gets the data, exactly as it was sent. We'll do two things with it: echo it back reversed and we will write it to a file on the server. The first part is easy: anything in an echo statement is sent back to our app:

echo "Data received from Device (reversed):" . strrev($myText); 

The second part involves a bit more PHP, but is straightforward. It writes the data which was received to a file.

 
$myFile = "AjaxPost/ajaxPost.txt";
 echo "<p>Writing data to " . getcwd() . $myFile;
 $f = fopen($myFile, 'w') or die("can't open file");
 fwrite($f, $myText);
 fclose($f);

What would you use this feature for?

  • Upload a JSON copy of your database.
  • Upload some pictures in Base64 format.
  • Create a .htm file which can be accessed as a web page.
  • Lots more ideas!

A tip on debugging PHP scripts Since PHP scripts run on the server and not on your screen, you don't get to see the error messages. This can make debugging difficult. If you put this statement at the top of your PHP script, the error messages will be echoed to your app:

ini_set('display_errors','1');

The error messages come back as HTML formatted text. The best way to look at them is to assign them to the innerText property of an HTMLview control.

Getting Data from Another Site

One of the basic security features of the modern web is the Same Origin Policy. It states that a web app cannot pull up just any data from another site. This becomes a problem if you need data on someone else's site.

Fortunately, they left an easy workaround. While a web app isn't allowed to access the files on another site, a PHP script is. We'll get our PHP script to do the dirty work for us and return the results to our app. The technique we will use is often called scraping.

Time to look at some code again. Here's the AppStudio part that calls the PHP script. It looks very much like the code in A Simple Exchange of Data with the server above. The main difference is that we're calling a different PHP script.

Function btnGetFile_onclick()
  req=Ajax("ajaxGetURL.php/?urlToGet=" & txtURL.value)
  If req.status=200 Then 'success
    htmResponse.innerHTML=req.responseText
  Else 'failure
    htmResponse.innerHTML=req.err
  End If
  htmResponse.refresh()
End Function

Before we talk about what is going to happen at the server end, let's see what the app looks like:


And here is what the PHP script looks like:

<?php
$ch = curl_init($_GET['urlToGet']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($ch);
curl_close($ch);
echo $data
?>

Let's take apart this one line:

  • $_GET('urlToGet') gets the parameter string that was attached to the URL in our AppStudio code.
  • _file_get_contents get the contents of the file, in this case, the URL that was passed.
  • echo sends the result back to our AppStudio program.

Pretty simple, isn't it?

(In this example, we're grabbing the robots.txt file from Microsoft's site, just to show we can get files from anywhere. Nearly all sites have a robots.txt file: it is used to guide search engines.)

There is a simpler way to do this, but it can run into security problems.

<?php
echo file_get_contents($_GET['urlToGet']); 
?>

How fast is it?

If your app is going to communicate with your server while it is running, you've probably wondered how much your app will slow down when it has to wait for the server.

In this blog post, we're going to make a program to test this. We'll construct a little program which sends data to the server as many times as it can. The server will record the information in a log file. Here is what our app will do:

  Do Until SysInfo(10) > limit
    req=Ajax("ajaxLog.php/?myText=" + Now)
    counter=counter+1
  Loop

SysInfo(10) is the current time in milliseconds. Limit is the time we want run to. You can run this test for up to about 5 seconds: after that, the system will think you are in a endless loop and shut you down.

On the server side, we need a PHP script to get the messages and write them out to disk. Here's the code:

<?php
  // read and append to file
  $myFile = "AjaxLog/log.txt";
  $f = fopen($myFile, 'a') or die("can't open file");
  fwrite($f, $_GET['myText'] . Chr(13) . Chr(10));
  fclose($f);
?>

Now, let's run it on a few different devices and see how many accesses we can do per second:

Desktop (Ethernet) 2745.0
iPhone 5 (WiFi) 16.75
iPhone 5 (LTE) 13.0
iPhone 4 (WiFi) 10.5
iPhone (3G) 2.5
Nexus S (WiFi) 5.0
Kindle Fire (WiFi) 9.0


It's obvious that the speed that really depends on what kind of connection you have to the web. A hard wire to your router gets the best time. WiFi is much slower, and 3G is slower again. No real surprise here.

The speeds shown here probably are not what you will see if you run the same test. There are a number of factors that will affect the speed:

  • Type of data connection
  • Load on the network
  • Number of hops the data has to make to get to the server
  • Load on the server

(You can try this sample yourself - it is called AjaxLog in the Samples folder.)