소프트웨어 개발자로서 웹 애플리케이션이 작동하는 방식에 대한 완전한 계층적 이해가 있어야 합니다. 여기에는 브라우저, HTTP, HTML, 웹 서버, 요구 사항 처리 등 애플리케이션에서 사용되는 기술도 포함됩니다.
이 글에서는 URL을 입력할 때 백그라운드에서 어떤 일이 일어나는지 자세히 살펴보겠습니다~
1. 먼저 브라우저에 URL을 입력해야 합니다: 2. 브라우저가 도메인 이름의 IP 주소를 검색합니다탐색의 첫 번째 단계는 방문한 도메인 이름의 IP 주소를 찾는 것입니다. DNS 조회 과정은 다음과 같습니다.
DNS 재귀 검색은 아래 그림과 같습니다.
DNS에 대해 걱정스러운 점 중 하나는 wikipedia.org 또는 facebook.com과 같은 전체 도메인 이름이 단일 IP 주소에만 해당하는 것처럼 보인다는 것입니다. 다행히도 이러한 병목 현상을 제거하는 방법에는 여러 가지가 있습니다.
Cycle DNS는 DNS 조회 중 여러 IP가 반환되는 경우의 솔루션입니다. 예를 들어 Facebook.com은 실제로 4개의 IP 주소에 해당합니다. 로드 밸런서는 특정 IP 주소를 수신하고 네트워크 요청을 클러스터된 서버로 전달하는 하드웨어 장치입니다. 일부 대규모 사이트에서는 일반적으로 이 고가의 고성능 로드 밸런서를 사용합니다. 지역DNS는 사용자의 지리적 위치에 따라 도메인 이름을 여러 다른 IP 주소에 매핑하여 확장성을 향상시킵니다. 이렇게 하면 서로 다른 서버가 동기화 상태를 업데이트할 수 없지만 정적 콘텐츠를 매핑하는 데는 좋습니다. Anycast는 하나의 IP 주소를 여러 물리적 호스트에 매핑하는 라우팅 기술입니다. 문제는 Anycast가 TCP 프로토콜에 잘 적응하지 못하기 때문에 이러한 솔루션에서는 거의 사용되지 않는다는 것입니다.대부분의 DNS 서버는 지연 시간이 짧은 효율적인 DNS 조회를 위해 Anycast를 사용합니다.
Facebook 홈페이지와 같은 동적 페이지는 열자마자 브라우저 캐시에서 빠르게 또는 즉시 만료되므로 읽을 수 없다는 것은 의심의 여지가 없습니다.
따라서 브라우저는 Facebook이 위치한 서버로 다음 요청을 보냅니다.
GET http://facebook.com/ HTTP/1.1<br> Accept: application/x-ms-application, URL을 입력하면 background_HTML/Xhtml_Web 페이지 제작에서 정확히 무슨 일이 일어나는지/jpeg, application/xaml+xml, [...]<br> User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; [...]<br> Accept-Encoding: gzip, deflate<br> Connection: Keep-Alive<br> Host: facebook.com<br> Cookie: datr=1265876274-[...]; locale=en_US; lsd=WW[...]; c_user=2101[...]
GET 이 요청은 읽을 URL을 정의합니다: "http://facebook.com/". 브라우저는 자체적으로(User-Agent 헤더), 어떤 유형의 응답을 허용할지(Accept 및Accept-Encoding 헤더) 정의합니다. 연결 헤더는 후속 요청에 대해 TCP 연결을 닫지 않도록 서버에 요청합니다.
요청에는 해당 도메인 이름에 대해 브라우저에 저장된쿠키도 포함되어 있습니다. 이미 알고 계시겠지만, 쿠키는 페이지 요청 사이에 웹사이트의 상태를 추적하는 열쇠입니다. 이러한 방식으로 쿠키는 로그인 사용자 이름, 서버에서 할당한 비밀번호 및 일부 사용자 설정을 저장합니다. 쿠키는 클라이언트 컴퓨터에 텍스트 파일로 저장되며 각 요청과 함께 서버로 전송됩니다.
除了获取请求,还有一种是发送请求,它常在提交表单用到。发送请求通过URL传递其参数(e.g.: http://robozzle.com/puzzle.aspx?id=85)。发送请求在请求正文头之后发送其参数。
像“http://facebook.com/”中的斜杠是至关重要的。这种情况下,浏览器能安全的添加斜杠。而像“http: //example.com/folderOrFile”这样的地址,因为浏览器不清楚folderOrFile到底是文件夹还是文件,所以不能自动添加 斜杠。这时,浏览器就不加斜杠直接访问地址,服务器会响应一个重定向,结果造成一次不必要的握手。
图中所示为Facebook服务器发回给浏览器的响应:
HTTP/1.1 301 Moved Permanently<br> Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0,<br> pre-check=0<br> Expires: Sat, 01 Jan 2000 00:00:00 GMT<br> Location: http://www.facebook.com/<br> P3P: CP="DSP LAW"<br> Pragma: no-cache<br> Set-Cookie: made_write_conn=deleted; expires=Thu, 12-Feb-2009 05:09:50 GMT;<br> path=/; domain=.facebook.com; httponly<br> Content-Type: text/html; charset=utf-8<br> X-Cnection: close<br> Date: Fri, 12 Feb 2010 05:09:51 GMT<br> Content-Length: 0
服务器给浏览器响应一个301永久重定向响应,这样浏览器就会访问“http://www.facebook.com/” 而非“http://facebook.com/”。
为什么服务器一定要重定向而不是直接发会用户想看的网页内容呢?这个问题有好多有意思的答案。
其中一个原因跟搜索引擎排名有 关。你看,如果一个页面有两个地址,就像http://www.igoro.com/ 和http://igoro.com/,搜索引擎会认为它们是两个网站,结果造成每一个的搜索链接都减少从而降低排名。而搜索引擎知道301永久重定向是 什么意思,这样就会把访问带www的和不带www的地址归到同一个网站排名下。
还有一个是用不同的地址会造成缓存友好性变差。当一个页面有好几个名字时,它可能会在缓存里出现好几次。
现在,浏览器知道了“http://www.facebook.com/”才是要访问的正确地址,所以它会发送另一个获取请求:
GET http://www.facebook.com/ HTTP/1.1<br> Accept: application/x-ms-application, URL을 입력하면 background_HTML/Xhtml_Web 페이지 제작에서 정확히 무슨 일이 일어나는지/jpeg, application/xaml+xml, [...]<br> Accept-Language: en-US<br> User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; [...]<br> Accept-Encoding: gzip, deflate<br> Connection: Keep-Alive<br> Cookie: lsd=XW[...]; c_user=21[...]; x-referer=[...]<br> Host: www.facebook.com
头信息以之前请求中的意义相同。
6. 服务器“处理”请求服务器接收到获取请求,然后处理并返回一个响应。
这表面上看起来是一个顺向的任务,但其实这中间发生了很多有意思的东西- 就像作者博客这样简单的网站,何况像facebook那样访问量大的网站呢!
Web 服务器软件举 个最简单的例子,需求处理可以以映射网站地址结构的文件层次存储。像http://example.com/folder1/page1.aspx这个地 址会映射/httpdocs/folder1/page1.aspx这个文件。web服务器软件可以设置成为地址人工的对应请求处理,这样 page1.aspx的发布地址就可以是http://example.com/folder1/page1。
请求处理所 有动态网站都面临一个有意思的难点 -如何存储数据。小网站一半都会有一个SQL数据库来存储数据,存储大量数据和/或访问量大的网站不得不找一些办法把数据库分配到多台机器上。解决方案 有:sharding (基于主键值讲数据表分散到多个数据库中),复制,利用弱语义一致性的简化数据库。
委 托工作给批处理是一个廉价保持数据更新的技术。举例来讲,Fackbook得及时更新新闻feed,但数据支持下的“你可能认识的人”功能只需要每晚更新 (作者猜测是这样的,改功能如何完善不得而知)。批处理作业更新会导致一些不太重要的数据陈旧,但能使数据更新耕作更快更简洁。
图中为服务器生成并返回的响应:
HTTP/1.1 200 OK<br> Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0,<br> pre-check=0<br> Expires: Sat, 01 Jan 2000 00:00:00 GMT<br> P3P: CP="DSP LAW"<br> Pragma: no-cache<br> Content-Encoding: gzip<br> Content-Type: text/html; charset=utf-8<br> X-Cnection: close<br> Transfer-Encoding: chunked<br> Date: Fri, 12 Feb 2010 09:05:55 GMT<br> <br> 2b3Tn@[...]
整个响应大小为35kB,其中大部分在整理后以blob类型传输。
内容编码头告诉浏览器整个响应体用gzip算法进行压缩。解压blob块后,你可以看到如下期望的HTML:
br /> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><br>
关于压缩,头信息说明了是否缓存这个页面,如果缓存的话如何去做,有什么cookies要去设置(前面这个响应里没有这点)和隐私信息等等。
请注意报头中把Content-type设置为“text/html”。报头让浏览器将该响应内容以HTML形式呈现,而不是以文件形式下载它。浏览器会根据报头信息决定如何解释该响应,不过同时也会考虑像URL扩展内容等其他因素。
在浏览器没有完整接受全部HTML文档时,它就已经开始显示这个页面了:
9. 浏览器发送获取嵌入在HTML中的对象在浏览器显示HTML时,它会注意到需要获取其他地址内容的标签。这时,浏览器会发送一个获取请求来重新获得这些文件。
下面是几个我们访问facebook.com时需要重获取的几个URL:
图片这些地址都要经历一个和HTML读取类似的过程。所以浏览器会在DNS中查找这些域名,发送请求,重定向等等...
但 不像动态页面那样,静态文件会允许浏览器对其进行缓存。有的文件可能会不需要与服务器通讯,而从缓存中直接读取。服务器的响应中包含了静态文件保存的期限 信息,所以浏览器知道要把它们缓存多长时间。还有,每个响应都可能包含像版本号一样工作的ETag头(被请求变量的实体值),如果浏览器观察到文件的版本 ETag信息已经存在,就马上停止这个文件的传输。
试着猜猜看“fbcdn.net”在地址中代表什么?聪明的答案是"Facebook内容分发网络"。Facebook利用内容分发网络(CDN)分发像图片,CSS表和JavaScript文件这些静态文件。所以,这些文件会在全球很多CDN的数据中心中留下备份。
静态内容往往代表站点的带宽大小,也能通过CDN轻松的复制。通常网站会使用第三方的CDN。例如,Facebook的静态文件由最大的CDN提供商Akamai来托管。
举例来讲,当你试着ping static.ak.fbcdn.net的时候,可能会从某个akamai.net服务器上获得响应。有意思的是,当你同样再ping一次的时候,响应的服务器可能就不一样,这说明幕后的负载平衡开始起作用了。
Web 2.0의 위대한 정신에 따라 클라이언트는 페이지가 표시된 후에도 서버와 계속 연결을 유지합니다.
Facebook 채팅 기능을 예로 들면 서버와 지속적으로 연락하여 밝고 회색 친구들의 상태를 적시에 업데이트합니다. 아바타가 켜져 있는 친구의 상태를 업데이트하기 위해 브라우저에서 실행되는 JavaScript 코드는 서버에 비동기 요청을 보냅니다. 이 비동기 요청은 특정 주소로 전송되며 프로그래밍 방식으로 구성된 가져오기 또는 보내기 요청입니다. 여전히 Facebook 예에서 클라이언트는 친구 중 온라인 상태인 온라인 상태 정보를 얻기 위해 http://www.facebook.com/ajax/chat/buddy_list.php에 게시 요청을 보냅니다.
이 패턴을 언급할 때 서버가 XML 형식으로 응답하는 명확한 이유는 없지만 "AJAX", 즉 "비동기 JavaScript 및 XML"에 대해 이야기해야 합니다. 또 다른 예로 비동기 요청의 경우 Facebook은 일부 JavaScript 코드 조각을 반환합니다.
무엇보다도 fiddler는 브라우저에서 보낸 비동기 요청을 볼 수 있는 도구입니다. 실제로 이러한 요청을 수동적으로 감시할 수 있을 뿐만 아니라 적극적으로 수정하고 다시 보낼 수도 있습니다. AJAX 요청은 속이기 매우 쉽기 때문에 점수를 유지하는 온라인 게임 개발자를 매우 우울하게 만듭니다. (물론 그런 사람들에게 거짓말은 하지 마세요~)
Facebook 채팅 기능은 AJAX와 관련하여 서버에서 클라이언트로 데이터를 푸시하는 흥미로운 문제 사례를 제공합니다. HTTP는 요청-응답 프로토콜이기 때문에 채팅 서버는 클라이언트에 새 메시지를 보낼 수 없습니다. 대신 클라이언트는 몇 초마다 서버를 폴링하여 새 메시지가 있는지 확인해야 합니다.
장기 폴링은 이러한 상황이 발생할 때 서버 부하를 줄이는 흥미로운 기술입니다. 폴링 시 서버에 새 메시지가 없으면 클라이언트를 무시합니다. 제한 시간이 만료되기 전에 클라이언트로부터 새 메시지가 수신되면 서버는 완료되지 않은 요청을 찾아 응답으로 클라이언트에 새 메시지를 반환합니다.