整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

高级面试题!请描述下从输入URL到整个网页加载完毕发生了什么?

对接下来很多应届生面临找工作面试的问题,我将会总结一些前端面试常见的问题和大家分享。希望能帮助到即将进入职场的同学们。话不多说,我们开始吧。

今天讨论的题目有点难,不一定会在应届生面试上出现。但是前端工程师多了解一下这些知识总是有好处的。

问题:请描述下从输入URL到整个网页加载完毕发生了什么?

1 把URL分割成几个部分:协议、网络地址、资源路径。

  其中网络地址指示该连接网络上哪一台计算机,可以是域名或者IP地址,可以包括端口号;

  协议是从该计算机获取资源的方式,常见的是HTTP、FTP,不同协议有不同的通讯内容格式;

  资源路径指示从服务器上获取哪一项资源。

  例如:http://www.guokr.com/question/554991/

  协议部分:http   网络地址:www.guokr.com   资源路径:/question/554991/

2 如果地址不是一个IP地址,通过DNS(域名系统)将该地址解析成IP地址。

  IP地址对应着网络上一台计算机,DNS服务器本身也有IP,你的网络设置包含DNS服务器的IP。

  例如:www.guokr.com 不是一个IP,向DNS询问请求www.guokr.com 对应的IP,获得IP: 111.13.57.142。

  这个过程里,你的电脑直接询问的DNS服务器可能没有www.guokr.com 对应的IP,就会向它的上级服务器询问,上级服务器同样可能没有,就依此一层层向上找,最高可达根节点,找到或者全部找不到为止。

3 如果地址不包含端口号,根据协议的默认端口号确定一个。

  端口号之于计算机就像窗口号之于银行,一家银行有多个窗口,每个窗口都有个号码,不同窗口可以负责不同的服务。

  端口只是一个逻辑概念,和计算机硬件没有关系。 例如:www.guokr.com 不包含端口号,http协议默认端口号是80。

  如果你输入的url是http://www.guokr.com:8080/ ,那表示不使用默认的端口号,而使用指定的端口号8080。

4 向2和3确定的IP和端口号发起网络连接。

例如:向111.13.57.142的80端口发起连接

5 发送请求

根据http协议要求,组织一个请求的数据包,里面包含大量请求信息,包括请求的资源路径、你的身份 例如:用自然语言来表达这个数据包,大概就是:请求 /question/554991/ ,我的身份是xxxxxxx。

6 服务器响应请求

将数据返回给浏览器。数据可能是根据HTML协议组织的网页,里面包含页面的布局、文字。

  数据也可能是图片、脚本程序等。现在你可以用浏览器的“查看源代码”功能,感受一下服务器返回的是什么东东。

  如果资源路径指示的资源不存在,服务器就会返回著名的404错误。

7 嵌套内容获取

如果(6)返回的是一个页面,根据页面里一些外链的URL,例如图片的地址,按照(1)-(6)再次获取。

8 浏览器渲染

开始根据资源的类型,将资源组织成屏幕上显示的图像,这个过程叫渲染,网页渲染是浏览器最复杂、最核心的功能。

9 显示

将渲染好的页面图像显示出来,并开始响应用户的操作。

以上只是最基本的步骤,实际不可能就这么简单,一些可选的步骤例如网页缓存、连接池、加载策略、加密解密、代理中转等等都没有提及。

  即使基本步骤本身也有很复杂的子步骤,TCP/IP、DNS、HTTP、HTML:每一个都可以展开成庞大的课题,而浏览器的基础——操作系统、编译器、硬件等更是一个比一个复杂。

  不是计算机专业的同学看了上面的解释完全不明白是很正常的,可能会问为什么要搞得那么复杂,但我保证这每一个步骤都经过深思熟虑和时间的考验。

  你输入URL即可浏览互联网,而计算机系统在背后做了无数你看不到的工作,计算机各个子领域无数工程师为此付出你难以想象的努力。当你坐在电脑前享受这一切的时候,请感谢一下那些天才工程师。

如果你有自己的想法,欢迎你给我留言。

单击带有超链接的文件时,超链接的内容有多种,打开方式,如替换当前页打开,在新窗口打开等。而用来指定打开方式的是<a>标签的target属性。

如果在一个<a>标签内容含一个target属性,浏览器将会载入和显示用这个标签的href属性命名的、名称与这个目标吻合的框架或者窗口中的文档。如果这个指定名称或id的框架或者窗口不存在,浏览器将打开一个新窗口,并给这个窗口一个指定的标记,然后将新的文档载入那个窗口。从此以后,超链接文档就可以指向这个新的窗口。

target属性的代码格式如下:

<a target="value">

其中value有四个参数可用,这4个保留的目标名称用作特殊的文档重定向操作。

(1)-blank。浏览器总在一个新打开、未命名的窗口中载入目标文档。

(2)-self。这个目标的值对所有未指定目标的<a>标签是默认目标,使得目标文档载入并显示在相同的框架或者窗口中作为源文档。这个目标是多余且不必要的,除非和文档标题 <base>标签中的target属性一起使用。

(3)-parent。这个目标使得文档载入父窗口或者包含超链接引用的框架的框架集。如果这个引用是在窗口或者顶级框架中,那么它与目标-self等效。

(4)-top。这个目标使的文档载入包含这个超链接的窗口,用-tap目标将会清除所有被包含的框架并将文档载入整个浏览器窗口。

小提示:这些target的所有4个值都以下划线开始。任何其他用一个下划线作为开头的窗口或者目标都会被浏览器忽略,因此,不要将下划线作为文档中定义的任何框架name或id的第一个字符。

下面举例说明target属性的使用方法。

(1)编写代码如下图所示:

(2)在浏览器中打开文件,预览效果如下所示:

(3)单击超链接,在新窗口打开连接页面,下图所示

(4)修改代码并单击链接。

将“-blank”换成“-self”,即代码修改为“<a href="http://www.sina.com.cn" target="_self">新浪</a>”,单击链接后,直接在当前窗口打开新链接,如图所示:



在前面

今年国庆假期终于可以憋在家里了不用出门了,不用出去看后脑了,真的是一种享受。这么好的光阴怎么浪费,睡觉、吃饭、打豆豆这怎么可能(耍多了也烦),完全不符合我们程序员的作风,赶紧起来把文章写完。

这篇文章比较基础,在国庆期间的业余时间写的,这几天又完善了下,力求把更多的前端所涉及到的关于文件上传的各种场景和应用都涵盖了,若有疏漏和问题还请留言斧正和补充。

自测读不读

以下是本文所涉及到的知识点,break or continue ?

  • 文件上传原理
  • 最原始的文件上传
  • 使用 koa2 作为服务端写一个文件上传接口
  • 单文件上传和上传进度
  • 多文件上传和上传进度
  • 拖拽上传
  • 剪贴板上传
  • 大文件上传之分片上传
  • 大文件上传之断点续传
  • node 端文件上传

原理概述

原理很简单,就是根据 http 协议的规范和定义,完成请求消息体的封装和消息体的解析,然后将二进制内容保存到文件。

我们都知道如果要上传一个文件,需要把 form 标签的enctype设置为multipart/form-data,同时method必须为post方法。

那么multipart/form-data表示什么呢?

multipart互联网上的混合资源,就是资源由多种元素组成,form-data表示可以使用HTML Forms 和 POST 方法上传文件,具体的定义可以参考RFC 7578。

multipart/form-data 结构

看下 http 请求的消息体



  • 请求头:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryDCntfiXcSkPhS4PN 表示本次请求要上传文件,其中boundary表示分隔符,如果要上传多个表单项,就要使用boundary分割,每个表单项由———XXX开始,以———XXX结尾。

  • 消息体- Form Data 部分

每一个表单项又由Content-Type和Content-Disposition组成。

Content-Disposition: form-data 为固定值,表示一个表单元素,name 表示表单元素的 名称,回车换行后面就是name的值,如果是上传文件就是文件的二进制内容。

Content-Type:表示当前的内容的 MIME 类型,是图片还是文本还是二进制数据。

解析

客户端发送请求到服务器后,服务器会收到请求的消息体,然后对消息体进行解析,解析出哪是普通表单哪些是附件。

可能大家马上能想到通过正则或者字符串处理分割出内容,不过这样是行不通的,二进制buffer转化为string,对字符串进行截取后,其索引和字符串是不一致的,所以结果就不会正确,除非上传的就是字符串。

不过一般情况下不需要自行解析,目前已经有很成熟的三方库可以使用。

至于如何解析,这个也会占用很大篇幅,后面的文章在详细说。

最原始的文件上传

使用 form 表单上传文件

在 ie时代,如果实现一个无刷新的文件上传那可是费老劲了,大部分都是用 iframe 来实现局部刷新或者使用 flash 插件来搞定,在那个时代 ie 就是最好用的浏览器(别无选择)。

DEMO



这种方式上传文件,不需要 js ,而且没有兼容问题,所有浏览器都支持,就是体验很差,导致页面刷新,页面其他数据丢失。

HTML

 <form method="post" action="http://localhost:8100" enctype="multipart/form-data">

        选择文件:
            <input type="file" name="f1"/> input 必须设置 name 属性,否则数据无法发送<br/>
<br/>
            标题:<input type="text" name="title"/><br/><br/><br/>

        <button type="submit" id="btn-0">上 传</button>

</form>

复制代码

文件上传接口

服务端文件的保存基于现有的库koa-body结合 koa2实现服务端文件的保存和数据的返回。

在项目开发中,文件上传本身和业务无关,代码基本上都可通用。

在这里我们使用koa-body库来实现解析和文件的保存。

koa-body 会自动保存文件到系统临时目录下,也可以指定保存的文件路径。



然后在后续中间件内得到已保存的文件的信息,再做二次处理。

  • ctx.request.files.f1 得到文件信息,f1为input file 标签的 name
  • 获得文件的扩展名,重命名文件

NODE

/**
 * 服务入口
 */
var http = require('http');
var koaStatic = require('koa-static');
var path = require('path');
var koaBody = require('koa-body');//文件保存库
var fs = require('fs');
var Koa = require('koa2');

var app = new Koa();
var port = process.env.PORT || '8100';

var uploadHost= `http://localhost:${port}/uploads/`;

app.use(koaBody({
    formidable: {
        //设置文件的默认保存目录,不设置则保存在系统临时目录下  os
        uploadDir: path.resolve(__dirname, '../static/uploads')
    },
    multipart: true // 开启文件上传,默认是关闭
}));

//开启静态文件访问
app.use(koaStatic(
    path.resolve(__dirname, '../static') 
));

//文件二次处理,修改名称
app.use((ctx) => {
    var file = ctx.request.files.f1;//得道文件对象
    var path = file.path;
    var fname = file.name;//原文件名称
    var nextPath = path+fname;
    if(file.size>0 && path){
        //得到扩展名
        var extArr = fname.split('.');
        var ext = extArr[extArr.length-1];
        var nextPath = path+'.'+ext;
        //重命名文件
        fs.renameSync(path, nextPath);
    }
    //以 json 形式输出上传文件地址
    ctx.body = `{
        "fileUrl":"${uploadHost}${nextPath.slice(nextPath.lastIndexOf('/')+1)}"
    }`;
});

/**
 * http server
 */
var server = http.createServer(app.callback());
server.listen(port);
console.log('demo1 server start ......   ');
复制代码

CODE

https://github.com/Bigerfe/fe-learn-code/