Clients make requests; Servers give responses
HTTP's main concept is Request-Response. A client makes a request to a server and a server provides a response to the client. The most common example of a client is a browser, which makes requests to the website, the most common example of a server.
Client Server
+----------+ +----------+
| | Connection | |
| | | |
| +--------------> | |
| | | |
| | Request | |
| | | |
| +--------------> | |
| | | |
| | Response | |
| | | |
| | <--------------| |
| | | |
| | End Connection | |
| | | |
| | <--------------| |
+----------+ +----------+
Structure and Protocol
Requests and Responses use the same structure. They both have a (1) Start Line, (2) Headers and (3) Body. In a request, the start line indicates what the client is trying to access from the server, like a profile, blog post, or product, and it does this in the form of a path, like /user/profile.html. Aside from requesting data back from a server, a request can also tell the server to create or manipulate data, like create a user or pay for something. To standardize the types of things a client can ask the server to do, HTTP has methods that represent these actions. When a client wants to receive data, it uses the GET method. In general when a client wants to create data, it uses the POST method. If you want to learn more about methods, read the w3.org documentation on HTTP methods.Next we have headers. Headers indicate information about the request, like where it came from, how to cache, or what format the client is expecting in the response. In the example below, you can see that the User-Agent header's value is curl/7.30.0. The server can now see what program was making this request. This is how sites get browser statistics since each browser tells the server who it is in the User-Agent header. See the HTTP List of headers wiki for more info.
Finally we have the body. In our example below, there is no body in the request. The body is optional, and usually in GET requests, there is no body. For responses to a GET request, the response body contains the file requested (like the HTML for google.com). See the response example below to see what the body returns.
Example request:
Start Line: GET /user/profile.html HTTP/1.1
Headers: User-Agent: curl/7.30.0
Host: google.com
Accept: */*
Example response:
Start Line: HTTP/1.1 200 OK
Headers: Server: nginx/1.6.0
Date: Mon, 27 Oct 2014 12:54:47 GMT
Content-Type: text/html
Content-Length: 1349
Last-Modified: Thu, 03 Jul 2014 23:31:18 GMT
Connection: keep-alive
ETag: "53b5e7c6-545"
Accept-Ranges: bytes
Body: <!DOCTYPE html>
<html>
<head>
<title>Statefate</title>
...
</html>
Some tricks
HTTP follows a request/response pattern. This means that every action that happens in HTTP starts with a request, and ends with a response. However, before we can send the request, the client has to connect to the server. Once the client and server are connected, the request is made by a client (browser), and a response is made by a server (website). Once the response is sent, the connection is closed.
HTTP does not allow the server to send responses whenever it wants to. For example, when you are IMing your friend through a website, your browser needs to be told when a new message is coming in, but how can it know if the server cannot tell you? One way is to make a request every second to check for new messages. This is generally bad since the ideal solution is to only make a request when there is a new message. Another solution is to think of the chat messages as a streaming response. See the drawing below:
Here the server is sending multiple mini responses (chat messages) which make up the entire HTTP response and waits until they have all been sent (after everyone has signed off) to close the connection. How does this fit in the Structure of the response? Once we send the response headers, we can send chunks of the response body as new messages from your friend come in. The cool part is that a client can also send data in the request body even after it started to get a response from the server. Here is some example code to see this in action. To run this, you will need to install Nodejs. The response will echo the data you pass to it in the request body:
HTTP does not allow the server to send responses whenever it wants to. For example, when you are IMing your friend through a website, your browser needs to be told when a new message is coming in, but how can it know if the server cannot tell you? One way is to make a request every second to check for new messages. This is generally bad since the ideal solution is to only make a request when there is a new message. Another solution is to think of the chat messages as a streaming response. See the drawing below:
Client Server
+----------+ +----------+
| | | |
| | Request | |
| +--------------> | |
| | | |
| | Response | |
| | <--------------| |
| | | |
| | <--------------| |
| | | |
| | <--------------| |
| | | |
| | <--------------| |
| | | |
| | Close | |
| | <--------------| |
+----------+ +----------+
Here the server is sending multiple mini responses (chat messages) which make up the entire HTTP response and waits until they have all been sent (after everyone has signed off) to close the connection. How does this fit in the Structure of the response? Once we send the response headers, we can send chunks of the response body as new messages from your friend come in. The cool part is that a client can also send data in the request body even after it started to get a response from the server. Here is some example code to see this in action. To run this, you will need to install Nodejs. The response will echo the data you pass to it in the request body:
request.js
var http = require('http');
var options = {
"hostname": "localhost",
"port": 8009,
"method": "POST",
"path": "/"
};
var req = http.request(options, function(res) {
// console.log('headers', res.headers);
res.on('data', function(chunk) {
console.log('echo', '' + chunk);
});
});
module.exports = req;
response.js
var http = require('http');
http.createServer(function(req, res) {
console.log('starting request');
req.on('data', function(chunk) {
console.log('writing', '' + chunk);
res.write(chunk);
});
req.on('end', function() {
console.log('ending request');
res.end();
});
}).listen(8009);
Then run
$ node server.js &
$ node
> var req = require('./request');
> req.write('echo test');
...

No comments:
Post a Comment