https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest

에서 참조

XMLHttpRequest makes sending HTTP requests very easy.  You simply create an instance of the object, open a URL, and send the request.  The HTTP status of the result, as well as the result’s contents, are available in the request object when the transaction is completed. This page outlines some of the common and even slightly obscure use cases for this powerful JavaScript object.

Types of requests

A request made via XMLHttpRequest can fetch the data in one of two ways, asynchronously or synchronously. The type of request is dictated by the optional async property that is set on the XMLHttpRequest .open() method. If this property is set to false, then the XMLHttpRequest will be processed synchronously, otherwise the process will be done asynchronously. A detailed discussion and demonstrations of these two types of requests can be found on the synchronous and asynchronous requests page.

Handling responses

There are several types of response attributes defined by the W3C specification for XMLHttpRequest.  These tell the client making the XMLHttpRequest important information about the status of the response. For many use cases this is as straightforward as the following example:

1
2
3
4
5
6
7
8
var request = new XMLHttpRequest();
request.open('GET', 'http://www.mozilla.org', false);
request.send(); // because of "false" above, will block until the request is done 
                // and status is available. Not recommended, however it works for simple cases.
  
if (request.status === 200) {
  console.log(request.responseText);
}

There are some situations where the contents of a remote response from an XMLHttpRequest may not be handled as easily as the case above. A few of these cases where dealing with reponseXML and responseText involves some manipulation and analysis are outlined in the following sections.

Analyzing and manipulating the responseXML property

If you use XMLHttpRequest to get the content of a remote XML document, the responseXML property will be a DOM Object containing a parsed XML document, which can be hard to manipulate and analyze. There are four primary ways of analyzing this XML document:

  1. Using XPath to address (point to) parts of it.
  2. Using JXON to convert it into a JavaScript Object tree.
  3. Manually Parsing and serializing XML to strings or objects.
  4. Using XMLSerializer to serialize DOM trees to strings or to files.
  5. RegExp can be used if you always know the content of the XML document beforehand. You might want to remove line breaks, if you use RegExp to scan with regard to linebreaks. However, this method is a “last resort” since if the XML code changes slightly, the method will likely fail.

Analyzing and manipulating a responseText property containing an HTML document

Note: The W3C XMLHttpRequest specification has added HTML parsing support to XMLHttpRequest, which originally supported only XML parsing. This feature allows Web apps to obtain an HTML resource as a parsed DOM using XMLHttpRequest.responseXML property. Read the article about HTML in XMLHttpRequest for details.

If you use XMLHttpRequest to get the content of a remote HTML webpage, the responseText property is a string containing a “soup” of all the HTML tags, which can be hard to manipulate and analyze. There are three primary ways of analyzing this HTML soup string:

  1. Safely parsing with nsIScriptableUnescapeHTML will quickly convert the HTML string into DOM, while stripping out JavaScript and other advanced elements, including the <head> of the webpage.
  2. RegExp can be used if you always know the content of the HTML responseText beforehand. You might want to remove line breaks, if you use RegExp to scan with regard to linebreaks. However, this method is a “last resort” since if the HTML code changes slightly, the method will likely fail.
  3. Using a hidden chrome or content-level iframe to load up the webpage can also be done to then manipulate it as DOM, however there are security risks to giving remote code this level of privileged access, which can cause issues for the review of your addon. For example, if a webpage executes the common “document.location = redirecttothispage.html” command on load, this will get interpreted as changing the browser chrome location (document.location in an extension) as opposed to the webpage location (content.document.location in an extension), thus destroying all browser components. Alternatively, and somewhat safer, a responseText string attained through a XMLHttpRequest can be analyzed using RegExp to remove potential JavaScript problems, then loaded into the hidden iframe that you have set up:
document.getElementById("hiddenXULiframe").contentWindow.document.body.innerHTML = req.responseText

Using FormData objects

The FormData object lets you compile a set of key/value pairs to send using XMLHttpRequest. Its primarily intended for use in sending form data, but can be used independently from forms in order to transmit keyed data. The transmitted data is in the same format that the form’s submit() method would use to send the data if the form’s encoding type were set to “multipart/form-data”. FormData objects can be utilized in a number of ways with an XMLHttpRequest. For examples and explanations of how one can utilize FormData with XMLHttpRequests see the Using FormData Objects page.

Handling binary data

Although XMLHttpRequest is most commonly used to send and receive textual data, it can be used to send and receive binary content. There are several well tested methods for coercing the response of an XMLHttpRequest into sending binary data. These involve utilizing the .overrideMimeType() method on the XMLHttpRequest object and is a workable solution.

1
2
3
4
5
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
// retrieve data unprocessed as a binary string
xhr.overrideMimeType("text/plain; charset=x-user-defined");
/* ... */

The XMLHttpRequest Level 2 Specification adds new responseType attributes which make sending and receiving binary data much easier.

1
2
3
4
5
6
7
8
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.responseType = "arraybuffer"
xhr.onload = function(e) {
  var arraybuffer = xhr.response; // not responseText
  /* ... */
}
xhr.send();

For more examples check out the Sending and Receiving Binary Data page

Monitoring progress

XMLHttpRequest provides the ability to listen to various events that can occur while the request is being processed. This includes periodic progress notifications, error notifications, and so forth.

Support for DOM progress event monitoring of XMLHttpRequest transfers follows the Web API specification for progress events.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
var req = new XMLHttpRequest();
  
req.addEventListener("progress", updateProgress, false);
req.addEventListener("load", transferComplete, false);
req.addEventListener("error", transferFailed, false);
req.addEventListener("abort", transferCanceled, false);
  
req.open();
  
...
  
// progress on transfers from the server to the client (downloads)
function updateProgress(evt) {
  if (evt.lengthComputable) {
    var percentComplete = evt.loaded / evt.total;
    ...
  } else {
    // Unable to compute progress information since the total size is unknown
  }
}
  
function transferComplete(evt) {
  alert("The transfer is complete.");
}
  
function transferFailed(evt) {
  alert("An error occurred while transferring the file.");
}
  
function transferCanceled(evt) {
  alert("The transfer has been canceled by the user.");
}

Lines 3-6 add event listeners for the various events that are sent while performing a data transfer using XMLHttpRequest

Note: You need to add the event listeners before calling open() on the request.  Otherwise the progress events will not fire.

The progress event handler, specified by the updateProgress() function in this example, receives the total number of bytes to transfer as well as the number of bytes transferred so far in the event’s total and loaded fields.  However, if the lengthComputable field is false, the total length is not known and will be zero.

Progress events exist for both download and upload transfers. The download events are fired on the XMLHttpRequest object itself, as shown in the above sample. The upload events are fired on the XMLHttpRequest.upload object, as shown below:

1
2
3
4
5
6
7
8
var req = new XMLHttpRequest();
  
req.upload.addEventListener("progress", updateProgress, false);
req.upload.addEventListener("load", transferComplete, false);
req.upload.addEventListener("error", transferFailed, false);
req.upload.addEventListener("abort", transferCanceled, false);
  
req.open();
Note: Progress events are not available for the file: protocol.
Gecko 9.0 note

(Firefox 9.0 / Thunderbird 9.0 / SeaMonkey 2.6)

Starting in Gecko 9.0 (Firefox 9.0 / Thunderbird 9.0 / SeaMonkey 2.6), progress events can now be relied upon to come in for every chunk of data received, including the last chunk in cases in which the last packet is received and the connection closed before the progress event is fired. In this case, the progress event is automatically fired when the load event occurs for that packet. This lets you now reliably monitor progress by only watching the “progress” event.

Gecko 12.0 note

(Firefox 12.0 / Thunderbird 12.0 / SeaMonkey 2.9)

If your progress event is called with a responseType of “moz-blob”, the value of response is a Blob containing the data received so far.

One can also detect all three load-ending conditions (abort, load, or error) using the loadend event:

1
2
3
4
5
req.addEventListener("loadend", loadEnd, false);
  
function loadEnd(evt) {
  alert("The transfer finished (although we don't know if it succeeded or not).");
}

Note that there’s no way to be certain from the information received by the loadend event as to which condition caused the operation to terminate; however, you can use this to handle tasks that need to be performed in all end-of-transfer scenarios.

Cross-site XMLHttpRequest

Modern browsers support cross-site requests by implementing the web applications working group’s Access Control for Cross-Site Requests standard.  As long as the server is configured to allow requests from your web application’s origin, XMLHttpRequest will work.  Otherwise, an INVALID_ACCESS_ERR exception is thrown.

Bypassing the cache

Normally, XMLHttpRequest tries to retrieve content from the cache, if it’s available.  To bypass this, do the following:

1
2
3
4
var req = new XMLHttpRequest();
req.open('GET', url, false);
req.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
req.send(null);
Note: This approach will only work in Gecko-based software, as the channel attribute is Gecko-specific.

An alternate, cross-browser compatible approach is to append a timestamp to the URL, being sure to include a “?" or ”&“ as appropriate.  For example:

http://foo.com/bar.html

becomes

http://foo.com/bar.html?12345

and

http://foo.com/bar.html?foobar=baz

becomes

http://foo.com/bar.html?foobar=baz&12345

Since the local cache is indexed by URL, this causes every request to be unique, thereby bypassing the cache.

You can automatically adjust URLs using the following code:

1
2
3
var req = new XMLHttpRequest();
req.open("GET", url += ((/?/).test(url) ? "&" : "?") + (new Date()).getTime(), false);
req.send(null); 

Security

Firefox 3 note

Versions of Firefox prior to Firefox 3 allowed you to set the preference capability.policy.<policyname>.XMLHttpRequest.open</policyname> to allAccess to give specific sites cross-site access.  This is no longer supported.

Firefox 5 note

Versions of Firefox prior to Firefox 5 could use netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); to request cross-site access. This is no longer supported, even though it produces no warning and permission dialog is still presented.

The recommended way to enable cross-site scripting is to use the Access-Control-Allow-Origin HTTP header in the response to the XMLHttpRequest.

XMLHttpRequests being stopped

If you end up with an XMLHttpRequest having status=0 and statusText=null, it means that the request was not allowed to be performed. It was UNSENT. A likely cause for this is when the XMLHttpRequest origin (at the creation of the XMLHttpRequest) has changed when the XMLHttpRequest is then open(). This case can happen for example when one has an XMLHttpRequest that gets fired on an onunload event for a window: the XMLHttpRequest gets in fact created when the window to be closed is still there, and then the request is sent (ie open()) when this window has lost its focus and potentially different window has gained focus. The way to avoid this problem is to set a listener on the new window "activate” event that gets set when the old window has its “unload” event fired.

Downloading JSON and JavaScript from extensions

For security reasons, extensions should never use eval() to parse JSON or JavaScript code downloaded from the web.  See Downloading JSON and JavaScript in extensions for details.

Using XMLHttpRequest from JavaScript modules / XPCOM components

Instantiating XMLHttpRequest from a JavaScript module or an XPCOM component works a little differently; it can’t be instantiated using the XMLHttpRequest() constructor. The constructor is not defined inside components and the code results in an error. The best way to work around this is to use the XPCOM component constructor.

1
2
const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1");
var req = XMLHttpRequest();

Unfortunately in versions of Gecko prior to Gecko 16 there is a bug which can cause requests created this way to be cancelled for no reason.  If you need your code to work on Gecko 15 or earlier, you can get the XMLHttpRequest constructor from the hidden DOM window like so.

1
2
3
4
const { XMLHttpRequest } = Components.classes["@mozilla.org/appshell/appShellService;1"]
                                     .getService(Components.interfaces.nsIAppShellService)
                                     .hiddenDOMWindow;
var req = XMLHttpRequest();

See also

  1. MDC AJAX introduction
  2. HTTP access control
  3. How to check the security state of an XMLHTTPRequest over SSL
  4. XMLHttpRequest – REST and the Rich User Experience
  5. Microsoft documentation
  6. Apple developers’ reference
  7. “Using the XMLHttpRequest Object” (jibbering.com)
  8. The XMLHttpRequest Object: W3C Specification
  9. Web Progress Events specification
  10. Reading Ogg files with JavaScript (Chris Double)

https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest

에서 참조

XMLHttpRequest makes sending HTTP requests very easy.  You simply create an instance of the object, open a URL, and send the request.  The HTTP status of the result, as well as the result’s contents, are available in the request object when the transaction is completed. This page outlines some of the common and even slightly obscure use cases for this powerful JavaScript object.

Types of requests

A request made via XMLHttpRequest can fetch the data in one of two ways, asynchronously or synchronously. The type of request is dictated by the optional async property that is set on the XMLHttpRequest .open() method. If this property is set to false, then the XMLHttpRequest will be processed synchronously, otherwise the process will be done asynchronously. A detailed discussion and demonstrations of these two types of requests can be found on the synchronous and asynchronous requests page.

Handling responses

There are several types of response attributes defined by the W3C specification for XMLHttpRequest.  These tell the client making the XMLHttpRequest important information about the status of the response. For many use cases this is as straightforward as the following example:

1
2
3
4
5
6
7
8
var request = new XMLHttpRequest();
request.open('GET', 'http://www.mozilla.org', false);
request.send(); // because of "false" above, will block until the request is done 
                // and status is available. Not recommended, however it works for simple cases.
  
if (request.status === 200) {
  console.log(request.responseText);
}

There are some situations where the contents of a remote response from an XMLHttpRequest may not be handled as easily as the case above. A few of these cases where dealing with reponseXML and responseText involves some manipulation and analysis are outlined in the following sections.

Analyzing and manipulating the responseXML property

If you use XMLHttpRequest to get the content of a remote XML document, the responseXML property will be a DOM Object containing a parsed XML document, which can be hard to manipulate and analyze. There are four primary ways of analyzing this XML document:

  1. Using XPath to address (point to) parts of it.
  2. Using JXON to convert it into a JavaScript Object tree.
  3. Manually Parsing and serializing XML to strings or objects.
  4. Using XMLSerializer to serialize DOM trees to strings or to files.
  5. RegExp can be used if you always know the content of the XML document beforehand. You might want to remove line breaks, if you use RegExp to scan with regard to linebreaks. However, this method is a “last resort” since if the XML code changes slightly, the method will likely fail.

Analyzing and manipulating a responseText property containing an HTML document

Note: The W3C XMLHttpRequest specification has added HTML parsing support to XMLHttpRequest, which originally supported only XML parsing. This feature allows Web apps to obtain an HTML resource as a parsed DOM using XMLHttpRequest.responseXML property. Read the article about HTML in XMLHttpRequest for details.

If you use XMLHttpRequest to get the content of a remote HTML webpage, the responseText property is a string containing a “soup” of all the HTML tags, which can be hard to manipulate and analyze. There are three primary ways of analyzing this HTML soup string:

  1. Safely parsing with nsIScriptableUnescapeHTML will quickly convert the HTML string into DOM, while stripping out JavaScript and other advanced elements, including the <head> of the webpage.
  2. RegExp can be used if you always know the content of the HTML responseText beforehand. You might want to remove line breaks, if you use RegExp to scan with regard to linebreaks. However, this method is a “last resort” since if the HTML code changes slightly, the method will likely fail.
  3. Using a hidden chrome or content-level iframe to load up the webpage can also be done to then manipulate it as DOM, however there are security risks to giving remote code this level of privileged access, which can cause issues for the review of your addon. For example, if a webpage executes the common “document.location = redirecttothispage.html” command on load, this will get interpreted as changing the browser chrome location (document.location in an extension) as opposed to the webpage location (content.document.location in an extension), thus destroying all browser components. Alternatively, and somewhat safer, a responseText string attained through a XMLHttpRequest can be analyzed using RegExp to remove potential JavaScript problems, then loaded into the hidden iframe that you have set up:
document.getElementById("hiddenXULiframe").contentWindow.document.body.innerHTML = req.responseText

Using FormData objects

The FormData object lets you compile a set of key/value pairs to send using XMLHttpRequest. Its primarily intended for use in sending form data, but can be used independently from forms in order to transmit keyed data. The transmitted data is in the same format that the form’s submit() method would use to send the data if the form’s encoding type were set to “multipart/form-data”. FormData objects can be utilized in a number of ways with an XMLHttpRequest. For examples and explanations of how one can utilize FormData with XMLHttpRequests see the Using FormData Objects page.

Handling binary data

Although XMLHttpRequest is most commonly used to send and receive textual data, it can be used to send and receive binary content. There are several well tested methods for coercing the response of an XMLHttpRequest into sending binary data. These involve utilizing the .overrideMimeType() method on the XMLHttpRequest object and is a workable solution.

1
2
3
4
5
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
// retrieve data unprocessed as a binary string
xhr.overrideMimeType("text/plain; charset=x-user-defined");
/* ... */

The XMLHttpRequest Level 2 Specification adds new responseType attributes which make sending and receiving binary data much easier.

1
2
3
4
5
6
7
8
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.responseType = "arraybuffer"
xhr.onload = function(e) {
  var arraybuffer = xhr.response; // not responseText
  /* ... */
}
xhr.send();

For more examples check out the Sending and Receiving Binary Data page

Monitoring progress

XMLHttpRequest provides the ability to listen to various events that can occur while the request is being processed. This includes periodic progress notifications, error notifications, and so forth.

Support for DOM progress event monitoring of XMLHttpRequest transfers follows the Web API specification for progress events.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
var req = new XMLHttpRequest();
  
req.addEventListener("progress", updateProgress, false);
req.addEventListener("load", transferComplete, false);
req.addEventListener("error", transferFailed, false);
req.addEventListener("abort", transferCanceled, false);
  
req.open();
  
...
  
// progress on transfers from the server to the client (downloads)
function updateProgress(evt) {
  if (evt.lengthComputable) {
    var percentComplete = evt.loaded / evt.total;
    ...
  } else {
    // Unable to compute progress information since the total size is unknown
  }
}
  
function transferComplete(evt) {
  alert("The transfer is complete.");
}
  
function transferFailed(evt) {
  alert("An error occurred while transferring the file.");
}
  
function transferCanceled(evt) {
  alert("The transfer has been canceled by the user.");
}

Lines 3-6 add event listeners for the various events that are sent while performing a data transfer using XMLHttpRequest

Note: You need to add the event listeners before calling open() on the request.  Otherwise the progress events will not fire.

The progress event handler, specified by the updateProgress() function in this example, receives the total number of bytes to transfer as well as the number of bytes transferred so far in the event’s total and loaded fields.  However, if the lengthComputable field is false, the total length is not known and will be zero.

Progress events exist for both download and upload transfers. The download events are fired on the XMLHttpRequest object itself, as shown in the above sample. The upload events are fired on the XMLHttpRequest.upload object, as shown below:

1
2
3
4
5
6
7
8
var req = new XMLHttpRequest();
  
req.upload.addEventListener("progress", updateProgress, false);
req.upload.addEventListener("load", transferComplete, false);
req.upload.addEventListener("error", transferFailed, false);
req.upload.addEventListener("abort", transferCanceled, false);
  
req.open();
Note: Progress events are not available for the file: protocol.
Gecko 9.0 note

(Firefox 9.0 / Thunderbird 9.0 / SeaMonkey 2.6)

Starting in Gecko 9.0 (Firefox 9.0 / Thunderbird 9.0 / SeaMonkey 2.6), progress events can now be relied upon to come in for every chunk of data received, including the last chunk in cases in which the last packet is received and the connection closed before the progress event is fired. In this case, the progress event is automatically fired when the load event occurs for that packet. This lets you now reliably monitor progress by only watching the “progress” event.

Gecko 12.0 note

(Firefox 12.0 / Thunderbird 12.0 / SeaMonkey 2.9)

If your progress event is called with a responseType of “moz-blob”, the value of response is a Blob containing the data received so far.

One can also detect all three load-ending conditions (abort, load, or error) using the loadend event:

1
2
3
4
5
req.addEventListener("loadend", loadEnd, false);
  
function loadEnd(evt) {
  alert("The transfer finished (although we don't know if it succeeded or not).");
}

Note that there’s no way to be certain from the information received by the loadend event as to which condition caused the operation to terminate; however, you can use this to handle tasks that need to be performed in all end-of-transfer scenarios.

Cross-site XMLHttpRequest

Modern browsers support cross-site requests by implementing the web applications working group’s Access Control for Cross-Site Requests standard.  As long as the server is configured to allow requests from your web application’s origin, XMLHttpRequest will work.  Otherwise, an INVALID_ACCESS_ERR exception is thrown.

Bypassing the cache

Normally, XMLHttpRequest tries to retrieve content from the cache, if it’s available.  To bypass this, do the following:

1
2
3
4
var req = new XMLHttpRequest();
req.open('GET', url, false);
req.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
req.send(null);
Note: This approach will only work in Gecko-based software, as the channel attribute is Gecko-specific.

An alternate, cross-browser compatible approach is to append a timestamp to the URL, being sure to include a “?” or “&” as appropriate.  For example:

http://foo.com/bar.html

becomes

http://foo.com/bar.html?12345

and

http://foo.com/bar.html?foobar=baz

becomes

http://foo.com/bar.html?foobar=baz&12345

Since the local cache is indexed by URL, this causes every request to be unique, thereby bypassing the cache.

You can automatically adjust URLs using the following code:

1
2
3
var req = new XMLHttpRequest();
req.open("GET", url += ((/?/).test(url) ? "&" : "?") + (new Date()).getTime(), false);
req.send(null); 

Security

Firefox 3 note

Versions of Firefox prior to Firefox 3 allowed you to set the preference capability.policy.<policyname>.XMLHttpRequest.open</policyname> to allAccess to give specific sites cross-site access.  This is no longer supported.

Firefox 5 note

Versions of Firefox prior to Firefox 5 could use netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead"); to request cross-site access. This is no longer supported, even though it produces no warning and permission dialog is still presented.

The recommended way to enable cross-site scripting is to use the Access-Control-Allow-Origin HTTP header in the response to the XMLHttpRequest.

XMLHttpRequests being stopped

If you end up with an XMLHttpRequest having status=0 and statusText=null, it means that the request was not allowed to be performed. It was UNSENT. A likely cause for this is when the XMLHttpRequest origin (at the creation of the XMLHttpRequest) has changed when the XMLHttpRequest is then open(). This case can happen for example when one has an XMLHttpRequest that gets fired on an onunload event for a window: the XMLHttpRequest gets in fact created when the window to be closed is still there, and then the request is sent (ie open()) when this window has lost its focus and potentially different window has gained focus. The way to avoid this problem is to set a listener on the new window “activate” event that gets set when the old window has its “unload” event fired.

Downloading JSON and JavaScript from extensions

For security reasons, extensions should never use eval() to parse JSON or JavaScript code downloaded from the web.  See Downloading JSON and JavaScript in extensions for details.

Using XMLHttpRequest from JavaScript modules / XPCOM components

Instantiating XMLHttpRequest from a JavaScript module or an XPCOM component works a little differently; it can’t be instantiated using the XMLHttpRequest() constructor. The constructor is not defined inside components and the code results in an error. The best way to work around this is to use the XPCOM component constructor.

1
2
const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1");
var req = XMLHttpRequest();

Unfortunately in versions of Gecko prior to Gecko 16 there is a bug which can cause requests created this way to be cancelled for no reason.  If you need your code to work on Gecko 15 or earlier, you can get the XMLHttpRequest constructor from the hidden DOM window like so.

1
2
3
4
const { XMLHttpRequest } = Components.classes["@mozilla.org/appshell/appShellService;1"]
                                     .getService(Components.interfaces.nsIAppShellService)
                                     .hiddenDOMWindow;
var req = XMLHttpRequest();

See also

  1. MDC AJAX introduction
  2. HTTP access control
  3. How to check the security state of an XMLHTTPRequest over SSL
  4. XMLHttpRequest – REST and the Rich User Experience
  5. Microsoft documentation
  6. Apple developers’ reference
  7. “Using the XMLHttpRequest Object” (jibbering.com)
  8. The XMLHttpRequest Object: W3C Specification
  9. Web Progress Events specification
  10. Reading Ogg files with JavaScript (Chris Double)

https://developer.mozilla.org/en-US/docs/AJAX/Getting_Started

에서 참조

 

What’s AJAX?

AJAX stands for Asynchronous JavaScript and XML. In a nutshell, it is the use of the XMLHttpRequest object to communicate with server-side scripts. It can send as well as receive information in a variety of formats, including JSON, XML, HTML, and even text files. AJAX’s most appealing characteristic, however, is its “asynchronous” nature, which means it can do all of this without having to refresh the page. This lets you update portions of a page based upon user events.

The two features in question are that you can:

  • Make requests to the server without reloading the page
  • Receive and work with data from the server

Step 1 – How to make an HTTP request

In order to make an HTTP request to the server using JavaScript, you need an instance of a class that provides this functionality. Such a class was originally introduced in Internet Explorer as an ActiveX object, called XMLHTTP. Then Mozilla, Safari, and other browsers followed, implementing an XMLHttpRequest class that supports the methods and properties of Microsoft’s original ActiveX object.

As a result, in order to create a cross-browser instance (object) of the required class, you can do the following:

1
2
3
4
5
6
var httpRequest;
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
    httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE 8 and older
    httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
Note: For illustration purposes, the above is a somewhat simplified version of the code to be used for creating an XMLHTTP instance. For a more real-life example, see step 3 of this article.

Next, you need to decide what you want to do after you receive the server response to your request. At this stage, you just need to tell the HTTP request object which JavaScript function will handle processing the response. This is done by setting the onreadystatechange property of the object to the name of the JavaScript function that should be called when the state of the request changes, like this:

httpRequest.onreadystatechange = nameOfTheFunction;

Note that there are no parentheses after the function name and no parameters passed, because you’re simply assigning a reference to the function, rather than actually calling it. Also, instead of giving a function name, you can use the JavaScript technique of defining functions on the fly (called “anonymous functions”) and define the actions that will process the response right away, like this:

1
2
3
httpRequest.onreadystatechange = function(){
    // process the server response
};

Next, after you’ve declared what will happen as soon as you receive the response, you need to actually make the request. You need to call the open() and send() methods of the HTTP request class, like this:

1
2
httpRequest.open('GET', 'http://www.example.org/some.file', true);
httpRequest.send(null);
  • The first parameter of the call to open() is the HTTP request method – GET, POST, HEAD or any other method you want to use and that is supported by your server. Keep the method capitalized as per the HTTP standard; otherwise some browsers (like Firefox) might not process the request. For more information on the possible HTTP request methods you can check the W3C specs.
  • The second parameter is the URL of the page you’re requesting. As a security feature, you cannot call pages on 3rd-party domains. Be sure to use the exact domain name on all of your pages or you will get a “permission denied” error when you call open(). A common pitfall is accessing your site by domain.tld, but attempting to call pages with www.domain.tld. If you really need to send a request to another domain, see HTTP access control.
  • The optional third parameter sets whether the request is asynchronous. If TRUE (the default), the execution of the JavaScript function will continue while the response of the server has not yet arrived. This is the A in AJAX.

The parameter to the send() method can be any data you want to send to the server if POST-ing the request. Form data should be sent in a format that the server can parse easily. This can be as a query string, like:

"name=value&anothername="+encodeURIComponent(myVar)+"&so=on"

or in several other formats, including JSON, SOAP, etc.

Note that if you want to POST data, you may have to set the MIME type of the request. For example, use the following line before calling send() for form data sent as a query string:

1
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

Step 2 – Handling the server response

Remember that when you were sending the request, you provided the name of a JavaScript function that is designed to handle the response.

1
httpRequest.onreadystatechange = nameOfTheFunction;

Let’s see what this function should do. First, the function needs to check for the state of the request. If the state has the value of 4, that means that the full server response has been received and it’s OK for you to continue processing it.

1
2
3
4
5
if (httpRequest.readyState === 4) {
    // everything is good, the response is received
} else {
    // still not ready
}

The full list of the readyState values is as follows:

  • 0 (uninitialized)
  • 1 (loading)
  • 2 (loaded)
  • 3 (interactive)
  • 4 (complete)

(Source)

The next thing to check is the response code of the HTTP server response. All the possible codes are listed on the W3C site. In the following example, we differentiate between a successful or unsuccessful AJAX call by checking for a  200 OK response code.

1
2
3
4
5
6
7
if (httpRequest.status === 200) {
    // perfect!
} else {
    // there was a problem with the request,
    // for example the response may contain a 404 (Not Found)
    // or 500 (Internal Server Error) response code
}

Now after you’ve checked the state of the request and the HTTP status code of the response, it’s up to you to do whatever you want with the data the server has sent to you. You have two options to access that data:

  • httpRequest.responseText – returns the server response as a string of text
  • httpRequest.responseXML – returns the response as an XMLDocument object you can traverse using the JavaScript DOM functions

Note that the steps above are only valid if you used an asynchronous request (third parameter of open() was set to true). If you used an synchronous request you don’t need to specify a function, you can access the data return by the server right after calling send(), because the script will stop and wait for the server answer.

Step 3 – A Simple Example

Let’s put it all together and do a simple HTTP request. Our JavaScript will request an HTML document, test.html, which contains the text “I’m a test.” and then we’ll alert() the contents of the test.html file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<span id="ajaxButton" style="cursor: pointer; text-decoration: underline">
  Make a request
</span>
<script type="text/javascript">
(function() {
  var httpRequest;
  document.getElementById("ajaxButton").onclick = function() { makeRequest('test.html'); };
  
  function makeRequest(url) {
    if (window.XMLHttpRequest) { // Mozilla, Safari, ...
      httpRequest = new XMLHttpRequest();
    } else if (window.ActiveXObject) { // IE
      try {
        httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
     
      catch (e) {
        try {
          httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
       
        catch (e) {}
      }
    }
  
    if (!httpRequest) {
      alert('Giving up 🙁 Cannot create an XMLHTTP instance');
      return false;
    }
    httpRequest.onreadystatechange = alertContents;
    httpRequest.open('GET', url);
    httpRequest.send();
  }
  
  function alertContents() {
    if (httpRequest.readyState === 4) {
      if (httpRequest.status === 200) {
        alert(httpRequest.responseText);
      } else {
        alert('There was a problem with the request.');
      }
    }
  }
})();
</script>

In this example:

  • The user clicks the link “Make a request” in the browser;
  • The event handler calls the makeRequest() function with a parameter – the name test.html of an HTML file in the same directory;
  • The request is made and then (onreadystatechange) the execution is passed to alertContents();
  • alertContents() checks if the response was received and it’s an OK and then alert()s the contents of the test.html file.
Note: If you’re sending a request to a piece of code that will return XML, rather than to a static XML file, you must set some response headers if your page is to work in Internet Explorer in addition to Mozilla. If you do not set header Content-Type: application/xml, IE will throw a JavaScript error, “Object Expected”, after the line where you try to access an XML element. 
Note 2: If you do not set header Cache-Control: no-cache the browser will cache the response and never re-submit the request, making debugging “challenging.” You can also append an always-diferent aditional GET parameter, like the timestamp or a random number (see bypassing the cache)
Note 3: If the httpRequest variable is used globally, competing functions calling makeRequest() may overwrite each other, causing a race condition. Declaring the httpRequest variable local to a closure containing the AJAX functions prevents the race condition.
Note 4: In the event of a communication error (such as the webserver going down), an exception will be thrown in the onreadystatechange method when attempting to access the status field. Make sure that you wrap your if…then statement in a try…catch. (See: bug 238559).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function alertContents(httpRequest) {
  try {
    if (httpRequest.readyState === 4) {
      if (httpRequest.status === 200) {
        alert(httpRequest.responseText);
      } else {
        alert('There was a problem with the request.');
      }
    }
  }
  catch( e ) {
    alert('Caught Exception: ' + e.description);
  }
}

Step 4 – Working with the XML response

In the previous example, after the response to the HTTP request was received we used the responseText property of the request object, which contained the contents of the test.html file. Now let’s try the responseXML property.

First off, let’s create a valid XML document that we’ll request later on. The document (test.xml) contains the following:

1
2
3
4
<?xml version="1.0" ?>
<root>
    I'm a test.
</root>

In the script we only need to change the request line to:

1
2
3
...
onclick="makeRequest('test.xml')">
...

Then in alertContents(), we need to replace the line alert(httpRequest.responseText); with:

1
2
3
var xmldoc = httpRequest.responseXML;
var root_node = xmldoc.getElementsByTagName('root').item(0);
alert(root_node.firstChild.data);

This code takes the XMLDocument object given by responseXML and uses DOM methods to access some of the data contained in the XML document. You can see the test.xml here and the updated test script here.

Step 5 – Working with data

Finally, let’s send some data to the server and receive a response. Our JavaScript will request a dynamic page this time, test.php, which will take the data we send and return a “computed” string – “Hello, [user data]!” – which we’ll alert().

First we’ll add a text box to our HTML so the user can enter their name:

1
2
3
4
5
6
<label>Your name: 
  <input type="text" id="ajaxTextbox" />
</label>
<span id="ajaxButton" style="cursor: pointer; text-decoration: underline">
  Make a request
</span>

We’ll also add a line to our event handler to get the user’s data from the text box and send it to the makeRequest() function along with the URL of our server-side script:

1
2
3
4
  document.getElementById("ajaxButton").onclick = function() { 
      var userName = document.getElementById("ajaxTextbox").value;
      makeRequest('test.php',userName); 
  };

We need to modify makeRequest() to accept the user data and pass it along to the server. We’ll change the request method from GET to POST, and include our data as a parameter in the call to httpRequest.send():

1
2
3
4
5
6
7
8
9
  function makeRequest(url, userName) {
  
    ...
  
    httpRequest.onreadystatechange = alertContents;
    httpRequest.open('POST', url);
    httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    httpRequest.send('userName=' + encodeURIComponent(userName));
  }

The function alertContents() can be written the same way it was in Step 3 to alert our computed string, if that’s all the server returns. However, let’s say the server is going to return both the computed string and the original user data. So if our user typed “Jane” in the text box, the server’s response would look like this:

{"userData":"Jane","computedString":"Hi, Jane!"}

To use this data within alertContents(), we can’t just alert the responseText, we have to parse it and alert computedString, the property we want:

1
2
3
4
5
6
7
8
9
function alertContents() {
    if (httpRequest.readyState === 4) {
      if (httpRequest.status === 200) {
        var response = JSON.parse(httpRequest.responseText);
        alert(response.computedString);
    } else {
      alert('There was a problem with the request.');
    }
}

https://developer.mozilla.org/en-US/docs/AJAX/Getting_Started

에서 참조

 

What’s AJAX?

AJAX stands for Asynchronous JavaScript and XML. In a nutshell, it is the use of the XMLHttpRequest object to communicate with server-side scripts. It can send as well as receive information in a variety of formats, including JSON, XML, HTML, and even text files. AJAX’s most appealing characteristic, however, is its “asynchronous” nature, which means it can do all of this without having to refresh the page. This lets you update portions of a page based upon user events.

The two features in question are that you can:

  • Make requests to the server without reloading the page
  • Receive and work with data from the server

Step 1 – How to make an HTTP request

In order to make an HTTP request to the server using JavaScript, you need an instance of a class that provides this functionality. Such a class was originally introduced in Internet Explorer as an ActiveX object, called XMLHTTP. Then Mozilla, Safari, and other browsers followed, implementing an XMLHttpRequest class that supports the methods and properties of Microsoft’s original ActiveX object.

As a result, in order to create a cross-browser instance (object) of the required class, you can do the following:

1
2
3
4
5
6
var httpRequest;
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
    httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE 8 and older
    httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
Note: For illustration purposes, the above is a somewhat simplified version of the code to be used for creating an XMLHTTP instance. For a more real-life example, see step 3 of this article.

Next, you need to decide what you want to do after you receive the server response to your request. At this stage, you just need to tell the HTTP request object which JavaScript function will handle processing the response. This is done by setting the onreadystatechange property of the object to the name of the JavaScript function that should be called when the state of the request changes, like this:

httpRequest.onreadystatechange = nameOfTheFunction;

Note that there are no parentheses after the function name and no parameters passed, because you’re simply assigning a reference to the function, rather than actually calling it. Also, instead of giving a function name, you can use the JavaScript technique of defining functions on the fly (called “anonymous functions”) and define the actions that will process the response right away, like this:

1
2
3
httpRequest.onreadystatechange = function(){
    // process the server response
};

Next, after you’ve declared what will happen as soon as you receive the response, you need to actually make the request. You need to call the open() and send() methods of the HTTP request class, like this:

1
2
httpRequest.open('GET', 'http://www.example.org/some.file', true);
httpRequest.send(null);
  • The first parameter of the call to open() is the HTTP request method – GET, POST, HEAD or any other method you want to use and that is supported by your server. Keep the method capitalized as per the HTTP standard; otherwise some browsers (like Firefox) might not process the request. For more information on the possible HTTP request methods you can check the W3C specs.
  • The second parameter is the URL of the page you’re requesting. As a security feature, you cannot call pages on 3rd-party domains. Be sure to use the exact domain name on all of your pages or you will get a “permission denied” error when you call open(). A common pitfall is accessing your site by domain.tld, but attempting to call pages with www.domain.tld. If you really need to send a request to another domain, see HTTP access control.
  • The optional third parameter sets whether the request is asynchronous. If TRUE (the default), the execution of the JavaScript function will continue while the response of the server has not yet arrived. This is the A in AJAX.

The parameter to the send() method can be any data you want to send to the server if POST-ing the request. Form data should be sent in a format that the server can parse easily. This can be as a query string, like:

"name=value&anothername="+encodeURIComponent(myVar)+"&so=on"

or in several other formats, including JSON, SOAP, etc.

Note that if you want to POST data, you may have to set the MIME type of the request. For example, use the following line before calling send() for form data sent as a query string:

1
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

Step 2 – Handling the server response

Remember that when you were sending the request, you provided the name of a JavaScript function that is designed to handle the response.

1
httpRequest.onreadystatechange = nameOfTheFunction;

Let’s see what this function should do. First, the function needs to check for the state of the request. If the state has the value of 4, that means that the full server response has been received and it’s OK for you to continue processing it.

1
2
3
4
5
if (httpRequest.readyState === 4) {
    // everything is good, the response is received
} else {
    // still not ready
}

The full list of the readyState values is as follows:

  • 0 (uninitialized)
  • 1 (loading)
  • 2 (loaded)
  • 3 (interactive)
  • 4 (complete)

(Source)

The next thing to check is the response code of the HTTP server response. All the possible codes are listed on the W3C site. In the following example, we differentiate between a successful or unsuccessful AJAX call by checking for a  200 OK response code.

1
2
3
4
5
6
7
if (httpRequest.status === 200) {
    // perfect!
} else {
    // there was a problem with the request,
    // for example the response may contain a 404 (Not Found)
    // or 500 (Internal Server Error) response code
}

Now after you’ve checked the state of the request and the HTTP status code of the response, it’s up to you to do whatever you want with the data the server has sent to you. You have two options to access that data:

  • httpRequest.responseText – returns the server response as a string of text
  • httpRequest.responseXML – returns the response as an XMLDocument object you can traverse using the JavaScript DOM functions

Note that the steps above are only valid if you used an asynchronous request (third parameter of open() was set to true). If you used an synchronous request you don’t need to specify a function, you can access the data return by the server right after calling send(), because the script will stop and wait for the server answer.

Step 3 – A Simple Example

Let’s put it all together and do a simple HTTP request. Our JavaScript will request an HTML document, test.html, which contains the text “I’m a test.” and then we’ll alert() the contents of the test.html file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<span id="ajaxButton" style="cursor: pointer; text-decoration: underline">
  Make a request
</span>
<script type="text/javascript">
(function() {
  var httpRequest;
  document.getElementById("ajaxButton").onclick = function() { makeRequest('test.html'); };
  
  function makeRequest(url) {
    if (window.XMLHttpRequest) { // Mozilla, Safari, ...
      httpRequest = new XMLHttpRequest();
    } else if (window.ActiveXObject) { // IE
      try {
        httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
     
      catch (e) {
        try {
          httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
       
        catch (e) {}
      }
    }
  
    if (!httpRequest) {
      alert('Giving up 🙁 Cannot create an XMLHTTP instance');
      return false;
    }
    httpRequest.onreadystatechange = alertContents;
    httpRequest.open('GET', url);
    httpRequest.send();
  }
  
  function alertContents() {
    if (httpRequest.readyState === 4) {
      if (httpRequest.status === 200) {
        alert(httpRequest.responseText);
      } else {
        alert('There was a problem with the request.');
      }
    }
  }
})();
</script>

In this example:

  • The user clicks the link “Make a request” in the browser;
  • The event handler calls the makeRequest() function with a parameter – the name test.html of an HTML file in the same directory;
  • The request is made and then (onreadystatechange) the execution is passed to alertContents();
  • alertContents() checks if the response was received and it’s an OK and then alert()s the contents of the test.html file.
Note: If you’re sending a request to a piece of code that will return XML, rather than to a static XML file, you must set some response headers if your page is to work in Internet Explorer in addition to Mozilla. If you do not set header Content-Type: application/xml, IE will throw a JavaScript error, “Object Expected”, after the line where you try to access an XML element. 
Note 2: If you do not set header Cache-Control: no-cache the browser will cache the response and never re-submit the request, making debugging “challenging.” You can also append an always-diferent aditional GET parameter, like the timestamp or a random number (see bypassing the cache)
Note 3: If the httpRequest variable is used globally, competing functions calling makeRequest() may overwrite each other, causing a race condition. Declaring the httpRequest variable local to a closure containing the AJAX functions prevents the race condition.
Note 4: In the event of a communication error (such as the webserver going down), an exception will be thrown in the onreadystatechange method when attempting to access the status field. Make sure that you wrap your if…then statement in a try…catch. (See: bug 238559).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function alertContents(httpRequest) {
  try {
    if (httpRequest.readyState === 4) {
      if (httpRequest.status === 200) {
        alert(httpRequest.responseText);
      } else {
        alert('There was a problem with the request.');
      }
    }
  }
  catch( e ) {
    alert('Caught Exception: ' + e.description);
  }
}

Step 4 – Working with the XML response

In the previous example, after the response to the HTTP request was received we used the responseText property of the request object, which contained the contents of the test.html file. Now let’s try the responseXML property.

First off, let’s create a valid XML document that we’ll request later on. The document (test.xml) contains the following:

1
2
3
4
<?xml version="1.0" ?>
<root>
    I'm a test.
</root>

In the script we only need to change the request line to:

1
2
3
...
onclick="makeRequest('test.xml')">
...

Then in alertContents(), we need to replace the line alert(httpRequest.responseText); with:

1
2
3
var xmldoc = httpRequest.responseXML;
var root_node = xmldoc.getElementsByTagName('root').item(0);
alert(root_node.firstChild.data);

This code takes the XMLDocument object given by responseXML and uses DOM methods to access some of the data contained in the XML document. You can see the test.xml here and the updated test script here.

Step 5 – Working with data

Finally, let’s send some data to the server and receive a response. Our JavaScript will request a dynamic page this time, test.php, which will take the data we send and return a “computed” string – “Hello, [user data]!” – which we’ll alert().

First we’ll add a text box to our HTML so the user can enter their name:

1
2
3
4
5
6
<label>Your name: 
  <input type="text" id="ajaxTextbox" />
</label>
<span id="ajaxButton" style="cursor: pointer; text-decoration: underline">
  Make a request
</span>

We’ll also add a line to our event handler to get the user’s data from the text box and send it to the makeRequest() function along with the URL of our server-side script:

1
2
3
4
  document.getElementById("ajaxButton").onclick = function() { 
      var userName = document.getElementById("ajaxTextbox").value;
      makeRequest('test.php',userName); 
  };

We need to modify makeRequest() to accept the user data and pass it along to the server. We’ll change the request method from GET to POST, and include our data as a parameter in the call to httpRequest.send():

1
2
3
4
5
6
7
8
9
  function makeRequest(url, userName) {
  
    ...
  
    httpRequest.onreadystatechange = alertContents;
    httpRequest.open('POST', url);
    httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    httpRequest.send('userName=' + encodeURIComponent(userName));
  }

The function alertContents() can be written the same way it was in Step 3 to alert our computed string, if that’s all the server returns. However, let’s say the server is going to return both the computed string and the original user data. So if our user typed “Jane” in the text box, the server’s response would look like this:

{"userData":"Jane","computedString":"Hi, Jane!"}

To use this data within alertContents(), we can’t just alert the responseText, we have to parse it and alert computedString, the property we want:

1
2
3
4
5
6
7
8
9
function alertContents() {
    if (httpRequest.readyState === 4) {
      if (httpRequest.status === 200) {
        var response = JSON.parse(httpRequest.responseText);
        alert(response.computedString);
    } else {
      alert('There was a problem with the request.');
    }
}

Send a Request To a Server

To send a request to a server, we use the open() and send() methods of the XMLHttpRequest object:

xmlhttp.open(“GET”,“ajax_info.txt”,true);
xmlhttp.send();

Method Description open(method,url,async) Specifies the type of request, the URL, and if the request should be handled asynchronously or not.

method: the type of request: GET or POST
url: the location of the file on the server
async: true (asynchronous) or false (synchronous) send(string) Sends the request off to the server.

string: Only used for POST requests


GET or POST?

GET is simpler and faster than POST, and can be used in most cases.

However, always use POST requests when:

  • A cached file is not an option (update a file or database on the server)
  • Sending a large amount of data to the server (POST has no size limitations)
  • Sending user input (which can contain unknown characters), POST is more robust and secure than GET

Send a Request To a Server

To send a request to a server, we use the open() and send() methods of the XMLHttpRequest object:

xmlhttp.open(“GET”,”ajax_info.txt”,true);
xmlhttp.send();

Method Description open(method,url,async) Specifies the type of request, the URL, and if the request should be handled asynchronously or not.

method: the type of request: GET or POST
url: the location of the file on the server
async: true (asynchronous) or false (synchronous) send(string) Sends the request off to the server.

string: Only used for POST requests


GET or POST?

GET is simpler and faster than POST, and can be used in most cases.

However, always use POST requests when:

  • A cached file is not an option (update a file or database on the server)
  • Sending a large amount of data to the server (POST has no size limitations)
  • Sending user input (which can contain unknown characters), POST is more robust and secure than GET

http://misako.co.kr/articles/HttpVSHttps.aspx

에서 참조

 

HTTP 대 HTTPS : 뭐가 다른가?

신정훈

  웹 브라우저의 주소창을 자세히 보면 http://나 https://로 시작한다. 사실 http://는 하도 흔해서 생략하고 주소를 쳐도, 웹 브라우저가 알아서 http://를 넣어 준다. 어제 인터넷에서 GMail 옵션 중에 항상 https를 사용하도록 하는 옵션이 있다고 그걸 쓰라는 글을 보았다. 거기 달린 답글 중에 두 개가 뭐가 다른지 모르겠다고 하는 글이 있었다. 그럼 이 두 개의 차이는 뭘까? 이름도 비슷한데. html하고 http는 다른 건가? 나도 예전에는 헛갈렸었다. 그럼 이들에 대해서 내가 아는 범위 내에서 간단히 설명을 하겠다.

HTML이란

   우리가 보는 웹 페이지의 대부분은 확장자가 html이다. htm인 것도 있는데, 그것은 예전 도스 기준으로 확장자가 3자밖에 되지 않기 때문에 어쩔 수 없이 끝을 자른 것으로 요즘은 잘 없다. 기타 php, aspx, jsp 등도 있다. 이들은 각각 웹 서버의 처리 엔진에 따른 결과물인데, 사실 확장자는 중요한 게 아니다. 어차피 확장자가 php,aspx,jsp인 것도 다들 html이다. 웹 브라우저는 확장자를 보고 이게 html인 줄 아는 게 아니라, 헤더에 있는 타입을 보고 아는 것이다. 우리가 보기에 확장자가 php라도, 헤더에는 txt/html로 타입이 규정되어 있고, 웹 브라우저는 그래서 이게 html인 줄 안다. 웹 페이지는 메모장으로 소스 보기를 하면 보이듯이 <tag>이런 태그로 둘러싸인 텍스트 문서이다. 그림 파일이나 다른 요소는 따로 표시되어 있지 페이지 속에 들어가지 않는다.

HTTP란

  Http는 이런 HTML 같은 문서를 웹 브라우저가 웹 서버에 요청하는 프로토콜이다. 프로토콜이라는 것은 일종의 대화 규칙이다. 우리가 폰뱅킹할 때를 보면 지정된 코드를 누르면 정해진 응답이 온다. 그런 것이다. 이게 없다면 웹 서버는 웹 브라우저가 무슨 페이지를 달라고 하는 건지도 모를 것이고 웹 브라우저도 웹 서버가 무슨 페이지를 보내는 건지 알 수가 없다. Http도 그냥 텍스트 교환일 뿐이다. 복잡한 바이너리 데이터가 아니라 그냥 텍스트 메시지를 주고 받는다. 물론 그 텍스트 메시지 안에 HTML 페이지도 들어 있다. 텍스트이기 때문에 만약 내가 있는 네트워크 안에서 누가 그 신호를 가로채어 본다면 내용이 그대로 보이게 된다. 만약 내가 메일을 읽고 있는데 누가 그 신호를 가로챈다면 메일 내용을 읽을 수 있을 것이다.

HTTPS란

  Https는 http하고 거의 같지만 모든 통신 내용을 암호화하는 것이 다르다. 사실 s가 secure socket, 즉 안전한 통신망을 뜻한다. 우리는 파일에 암호를 많이 걸어 봤다. 어떤 키를 설정해서 걸면 나중에 풀 때에도 그걸 입력해 푸는 것이다. 키라는 것은 암호화를 푸는 암호 즉 패스워드같은 것이다. 웹 서버가 키 하나를 정해서 페이지를 암호화해서 사용자의 웹 브라우저로 보내고 웹 브라우저는 그 키를 이용해서 페이지를 복원한다… 이러면 좋겠지만 이렇게 간단하지 않다. 웹 서버는 하나이지만 사용자는 불특정 다수이다. 그런데 키를 사용자들에게 줘 버리면 아무나 암호화를 풀 수 있게 된다. 영희에게 갈 페이지를 철수도 풀어서 볼 수 있게 되는데, 이러면 암호화의 효과가 없다.

 즉, 페이지 암호화 키가 그 페이지를 보는 특정 사용자에게만 알려져야 한다. 어떻게 이렇게 할 수 있을까? 이것이 바로 https 프로토콜이 하는 것이다. 위에서 말한 암호화 방식을 사용하되, 그 키를 다시 공개 키로 암호화하고 인증하는 것이다. 공개 키는 쉽게 말해서 데이터를 암호화하는데 키가 두 개 필요하다는 것이다. 암호화를 푸는 데에는 그 두 개 중 하나의 키만 있으면 된다. (수학적으로 로그 지수를 찾는 것이 어려운 문제에 기초하고 있다. 이렇게 자세한 것까지 알고 싶은 사람은 없겠지만.) 이게 무슨 뜻일까? 옥션 사이트에서는 A,B라는 키를 가지고 있다. 그리고 이 B라는 키만 사용자들에게 알려 준다. 그리고 옥션 사이트에 웹 브라우저가 연결을 시도할 때, 파일 암호화 키를 이 A,B 키로 암호화해서 보내 준다. 그러면 사용자들은 B라는 키로 데이터를 풀어 볼 수 있다. A는 옥션 관리자 말고는 아무도 모르기 때문에, B만 알아서는 옥션과 똑같이 암호화를 할 수 없다. 즉 사용자는 B로 풀어 봐서 풀어지면 이 데이터는 A키를 아는 옥션 관리자가 암호화한 것이라는 걸 알 수 있는 것이다. http 프로토콜의 경우 중간에서 네트워크 데이터를 가로채어서 마치 자기가 옥션 사이트인 것처럼 해서 가짜 페이지를 보낼 수도 있다. 하지만 https의 경우에는 A키를 모르기 때문에 중간에서 누가 그렇게 할 수가 없다. 이렇게 해서 반대편이 옥션이라는 것을 우리는 믿을 수 있다.

   이렇게 믿을 수 있으면 IE같은 브라우저에서는 주소 창의 색을 다르게 해서 안전하다고 알려 준다. 이렇게 해서 웹 서버와 사용자가 교환한 키로 전체 이후로는 HTML을 암호화해서 교환하는 것이다. 이렇게 되면 중간에서 웹 페이지를 누가 가로채어도 내용을 전혀 읽을 수 없다. 사실 시간이 주어진다면 암호화를 풀 수도 있다. 예를 들어 1024비트 암호화를 사용한다면 암호 키가 1024비트, 즉 2의 1024승이라는 것이다. 암호를 계산해서 푸는 방법은 없다 (있다면 그런 암호화는 폐기된다). 키를 모르고 암호화를 푼다는 것은 모든 키를 하나씩 다 대입해서 풀릴 때까지 해 보는 것이다. 그러면 위의 경우 평균적으로 2의 512승 번을 해 봐야 한다. 2의 512승과 2 x 512는 차원이 다르다. 2의 20승만 해도 백 만이 넘는다. 아무리 빠른 컴퓨터로 대입해도 아마 몇 천 년은 해야 할 것이다. 그래서 안전한 것이다.

결론

  그러면 https가 안전한데 다 https를 쓰지 http를 뭐하러 쓰느냐고 할 것이다. https 암호화를 하려면 웹 서버에 부하가 생기고, 위에서 말한 B가 그 서버의 인증서가 되는데, 이것은 Verisign 같은 업체에서 비싼 돈을 주고 사야하므로, 특히 우리 나라 웹 사이트들은 잘 쓰지 않는다. 하지만 외국 금융 사이트에서는 https는 필수이다. 또 http는 비연결형으로 웹 페이지를 보는 중 인터넷 연결이 끊겼다가 다시 연결되어도 페이지를 계속 볼 수 있지만 https의 경우에는 소켓 (데이터를 주고 받는 경로) 자체에서 인증을 하기 때문에 인터넷 연결이 끊기면 소켓도 끊어져서 다시 https 인증을 해야 한다. 그래서 시간이 또 걸린다.

   그래서 아무나 봐도 상관 없는 페이지는 http로, 남에게 보이면 안 되는 금융 정보나 메일 등 중요한 것은 https로 하는 것이다. GMail은 https를 지원한다. 다른 메일을 사용하는 사람은 보안 문제를 좀 더 생각해 보자.