网络

请求流程

浏览器请求一个网页的流程:
Client客户端 -DNS解析> IP地址 -TCP/IP三次握手> Sever服务端

注:

TCP/IP三次握手

  • 建立TCP连接
  • 发起HTTP请求

Client客户端 <- HTML代码 <-Sever服务端

Client客户端 -> 请求HTML中的静态资源渲染页面 -> Sever服务端

Client客户端 <- 四次挥手 中断连接请求 <-Sever服务端

关键:

  • 三次握手:请求连接时需要三次握手
  • 四次挥手:中断连接请求都需要4次往返的数据传输

URI

  • URI:Uniform Resource Identifier 同一资源标识符,用来唯一的标识一个资源
  • URL:Uniform Resourse Locator 统一资源定位符,URL可以用来标识一个资源,而且还指明了如何定位这个资源用地址定义一个资源
  • URN:Uniform Resource Name 统一资源命名,通过名字来表示资源的,用名称定位一个资源

URL可肯定是一个URI,URI并不一定时URL,也有可能时URN

URL 和 URN 是 URI 的子级

  • URI是资源标识
  • URL:

    • 资源标识
    • 具有定位资源的功能 (资源的具体位置)
    • 指明了获取资源所采用的协议

URL包含了:

协议名称 + 主机名称 + 端口号 + 路径 + 文件 + 查询所需字符串

  1. http:// jsplusplus.com:80/ Index/index.html ?a=1&b=2 #d

注:https默认端口号443 http默认端口号80

如何找一个人?

  1. 家庭住址 -> URL -> http://jsplusplus.com:80/ Index/index.html?a=1&b=2#d
  2. 姓名 + 身份证号 -> URN -> jsplusplus.com:80/ Index/index.html?a=1&b=2#d

客户端服务端

客户端:Client -> 客户所使用的电脑中的应用程序

服务端:Server -> 存放网页,客户端程序,数据处理程序,数据库的电脑

架构

C/S:Client Server 将应用程序安装在客户端电脑中,用服务端提供客户端所需要的数据

  • 优点:界面与操作丰富,安全性高,响应速度快
  • 缺点:通常用于局域网,需安装特定应用程序或特定硬件,维护成本高
  • 应用:pos机, 餐厅点餐系统

B/S:Browser Server 利用WEB浏览器呈现客户端程序界面,有服务器端提供客户端程序所需要的数据

  • 优点:无需安装客户端程序与特定硬件,多客户访问,交互性强,无需升级客户端
  • 缺点:跨浏览器兼容性差,功能性相对较弱,设计成本高,安全性弱,交互性弱
  • 应用:web端系统

服务器

购买/租赁服务器:实体服务器,云服务器(Elastic Compute Service)弹性计算服务

云服务器:无需提前采购硬件设备,而是根据业务需要,随时创建所需数量的云服务器

域名

Domain Name

  • 相当于访问互联网某一户人家的地址
  • 域名与服务器绑定以后,域名与服务器对应的IP是映射关系www.jd.com -> 111.13.28.118
  • 域名比IP更方便用户记忆
  • IP可以对应多个域名,所以不同的域名可以访问一个或多个WEB网页

根域名

根域名服务器

  • 主根服务器:1个 美国
  • 辅根服务器:12个 美国9个 英国瑞典1个 日本1个

管理机构:国际互联网名称与数学地址分配机制ICANN(美国授权)

前管理机构:商务部下属的国家通信与信息管理局(NTIA)外包给ICANN管理

作用:负责全球互联网域名根服务器,域名体系和IP地址的管理

www

万维网 World Wide Web

是用浏览器访问网页的服务,网站主页前需要加www

DNS解析

Domain Name Server(域名服务器)

作用:域名与对应ip转换的服务器

特征:DNS中保存了一张域名与对应的ip地址的表,一个域名对应一个ip地址,一个ip地址可以对应多个域名

关于gTLD:genericTop-Level DNS Server 顶级域名服务器,为所有.com, .net, …后缀做域名解析的服务器

DNS解析过程

网络 - 图1

解析顺序:

  1. .com
  2. jspp域名
  3. 二级域名

IP

Internet Protocol Address

互联网协议地址,IP地址

作用:分配给用户上网使用的互联网协议

分类:IPv4, IPv6,其他

IPv4形式:192.168.0.1(长度32位(4个字节),十进制表示)

IPv6形式:地址空间更大(8组(128位),十六进制)

IP端口号

PORT

例子:

IP地址:上海迪斯尼乐园 IPv4 / IPv6

端口号:乐园中的不同游乐设施 80 /443

总结:每一个端口对应的是一个服务器的一个业务,访问一个服务器的不同端口相当于访问不同的业务。

端口号范围:0-65535

默认端口:80http,443https,20,21FTP

TCP

如打电话的过程

TCP:Transmission Control Protocol 传输控制协议

特点:面向连接(收发数据前,必须建立可靠的连接)

建立连接基础:三次握手

应用场景:数据必须准确无误的收发,HTTP请求,FTP文件传输,邮件收发

优点:稳定,重传机制,拥塞控制机制,断开连接

缺点:速度慢,效率低,占用资源,容易被攻击(三次握手 -> DOS,DDOS攻击)

TCP/IP协议组:

提供点对点的连接机制,制定了数据封装,定址,传输,路由,数据接收的标准

建立TCP连接的前奏

标志位:数据包

  • SYN:Sychronize Sequence Numbers 同步序列编号
  • ACK:Acknowledgement 确认字符

状态:

  • LISTEN:侦听TCP端口的连接请求(我等着你发送连接请求呢)
  • SYN-SENT:在发送连接请求后等待匹配的连接请求(我发送了连接请求,我等你回复哈)
  • SYN-RECEIVED:在收到和发送一个连接请求后等待对连接请求的确认(我受到你的连接请求了哈,我等你回复我)
  • ESTABLISHED:代表一个打开的连接,数据可以传送给用户(数据建立了哈,我跟你说一下)

三次握手

网络 - 图2

UDP

如喇叭叫人

UDP:User Data Protocol 用户数据报协议

特点:面向无连接(不可靠的协议,无状态传输机制)

无连接信息发送机制

应用场景:无需确保通讯质量且要求速度快,无需确保信息完整

消息收发,语音通话,直播(QQ)

优点:安全,快速,漏洞少(UDP flood攻击)

缺点:不可靠,不稳定,容易丢包

总结:只要目的源地址,端口号确定,则可以直接发送信息报文,但不能保证一定能受到或受到完整的数据

HTTP&HTTPS

HTTP:HyperText Transfer Protocol 超文本传输协议

定义:客户端和服务器端请求和应答的标准,用于从WEB服务器传输超文本到本地浏览器的传输协议

HTTP请求:按照协议规则先向WEB服务器发送的将超文本传输到本地浏览器的请求

HTTPS:HyperText Transfer Proticol Secure 超文本传输安全协议

定义:HTTP的安全版 (安全基础是SSL/TLS)

  • SSL:Secure Sockets Layer 安全套接层
  • TLS:Transport Layer Security 传输层安全
  • 为网络通信提供安全及数据完整性的一种安全协议,对网络连接进行加密

区别:

  • HTTP是不安全的(监听和中间人攻击等手段,获取网站账户信息和敏感信息)
  • HTTP协议的传输内容都是明文,直接在TCP连接上运行,客户端和服务器都无法验证对方身份
  • HTTPS协议的传输内容是被SSL/TLS加密, 且运行在SSL/TLS上,SSL/TLS运行在TPC连接上,所以数据传输是安全的

报文

HTTP报文前言

HTTP基于TCP/IP通信协议来传递数据

HTTP基于客户端/服务端(C/S)架构模型

通过一个可靠的连接来交换信息,是一个无状态的请求/响应协议

限制每次连接只处理一个请求,服务器处理完客户的请求,并收到客户的应答后,即断开连接,采用这种方式可以节省传输时间

只要客户端和服务器直到如何处理的数据内容,任何类型的数据都可以通过HTTP发送,客户端以及服务器指定使用适合的MIME-type内容类型

Multipurpose Internet Mail Extensions type 多用途互联网邮件扩展类型

报文定义

在客户端与服务器之间发送的数据库,这些数据库以一些文本的元信息(meta-information)开头,描述了报文的内容及含义,后面跟着可选的数据部分,这些报文在客户端,服务器和代理之间流动,所以HTTP报文的发送也叫报文流。

  • 每条TTTP报文包含一个客户端请求和服务端响应
  • 请求报文Request和响应报文Response

报文如何发送

网络 - 图3

报文组成

  • 对报文进行描述的起始行
  • 包含属性的首部/头部(header)
  • 包含数据的主体(body)(可选项)

网络 - 图4

请求方式

报文请求方式:

  • GET/POST
  • OPTIONS:返回服务器针对特定资源所支持的HTTP请求方法
  • HEAD:返回与GET请求相一致的响应,响应体被返回
  • PUT:向指定资源位置上传其最新内容(form表单不支持)
  • DELETE:请求服务器删除request-URI所标识的资源(form表单不支持)
  • TRACE:回显服务器收到请求,主要用于测试或诊断
  • CONNECT:连接改为管道方式的代理服务器

put(增)

上传资源,form表单不支持,提交即存储的原则(无验证机制,安全漏洞),需配置服务器支持put方式转发到给后端操作

delete(删)

删除资源,form表单不支持,提交即删除的原则(无验证机制,安全漏洞),需配置服务器支持put方式转发到给够短操作

post(改)

修改资源

get(查)

获取资源

总结:

  • GET主要用来获取数据
  • GET的数据在请求体中是查询字符串参数(Query String Parameters)
  • POST主要用于传输数据到后端进行增加,删除,更新数据,提交表单
  • POST的数据在请求体中是表单数据(Form Data)

GET/POST区别

  • POST更安全,不会作为url一部分,不会被缓存,保存在服务器日志和浏览器记录中
  • POST发送的数据量更大(GET有url长度限制)
  • POST能发送更多的数据类型(各种类型的文件)
  • GET只能发送ASCII字符
  • POST比GET速度慢

    • POST请求包含更多的请求头
    • POST接收数据之前会先将请求头发给服务器确认,然后发送数据
  • POST不能进行管道话传输

GET过程:

  • 第三次握手,浏览器确认并发送请求头和数据
  • 服务器返回200 OK响应
  • GET会进行数据缓缓,POST不会

关于串行连接/持久化连接(keep-alive):

网络 - 图5

关于管道化持续连接:

把所有请求放到发送队列里,不等响应,一个一个发送请求的同时接收响应的响应

弊端:一旦出现连接问题,请求将被清空,重新再来,不合适更改数据

网络 - 图6

状态码

状态码 描述
1XX 信息,服务器收到请求,需要请求者继续执行操作
2XX 成功,操作被成功接收并处理
3XX 重定向,需要进一步的操作已完成请求
4XX 客户端错误,请求包含语法错误或无法完成请求
5XX 服务器错误,服务器在处理请求的过程中发生了错误

1xx:表示临时响应并需要请求者继续执行操作的状态码。

  • 100(继续)请求者应当继续提出请求。服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
  • 101(切换协议)请求者已要求服务器切换协议,服务器已确认并准备切换。只有在切换新的协议更有好处的时候才应该采取类似措施。
  • 102 Processing由WebDAV(RFC 2518)扩展的状态码,代表处理将被继续执行。

2xx:表示成功处理了请求的状态码。

  • 200(成功)服务器已成功处理了请求。通常,这表示服务器提供了请求的网页。如果是对您的robots.txt 文件显示此状态码,则表示 Googlebot 已成功检索到该文件。
  • 201(已创建)请求成功并且服务器创建了新的资源。
  • 202(已接受)服务器已接受请求,但尚未处理。
  • 203(非授权信息)服务器已成功处理了请求,但返回的信息可能来自另一来源。
  • 204(无内容)服务器成功处理了请求,但没有返回任何内容。
  • 205(重置内容)服务器成功处理了请求,但没有返回任何内容。与 204 响应不同,此响应要求请求者重置文档视图(例如,清除表单内容以输入新内容)。
  • 206(部分内容)服务器成功处理了部分 GET 请求。

3xx:要完成请求,需要进一步操作。通常,这些状态码用来重定向。Google 建议您在每次请求中使用重定向不要超过5 次。您可以使用网站管理员工具查看一下Googlebot 在抓取重定向网页时是否遇到问题。诊断下的网络抓取页列出了由于重定向错误导致 Googlebot 无法抓取的网址。

  • 300(多种选择)针对请求,服务器可执行多种操作。服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
  • 301(永久移动)请求的网页已永久移动到新位置。服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。您应使用此代码告诉某个网页或网站已永久移动到新位置。
  • 302(临时移动)服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来响应以后的请求。此代码与响应 GET 和 HEAD 请求的 301 代码类似,会自动将请求者转到不同的位置,但您不应使用此代码来告诉某个网页或网站已经移动,因为 Googlebot 会继续抓取原有位置并编制索引。
  • 303(查看其他位置)请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。对于除 HEAD 之外的所有请求,服务器会自动转到其他位置。
  • 304(未修改)自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容。
    如果网页自请求者上次请求后再也没有更改过,您应将服务器配置为返回此响应(称为 If-Modified-Since HTTP 标头)。服务器可以告诉 Googlebot 自从上次抓取后网页没有变更,进而节省带宽和开销。
  • 305(使用代理)请求者只能使用代理访问请求的网页。如果服务器返回此响应,还表示请求者应使用代理。
  • 307(临时重定向)服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来响应以后的请求。此代码与响应 GET 和 HEAD 请求的 301 代码类似,会自动将请求者转到不同的位置,但您不应使用此代码来告诉 Googlebot 某个页面或网站已经移动,因为 Googlebot 会继续抓取原有位置并编制索引。

4xx:这些状态码表示请求可能出错,妨碍了服务器的处理。

  • 400(错误请求)服务器不理解请求的语法。
  • 401(未授权)请求要求身份验证。对于登录后请求的网页,服务器可能返回此响应。
  • 403(禁止)服务器拒绝请求。如果您在 Googlebot 尝试抓取您网站上的有效网页时看到此状态码(您可以在 Google 网站管理员工具诊断下的网络抓取页面上看到此信息),可能是您的服务器或主机拒绝了 Googlebot 访问。
  • 404(未找到)服务器找不到请求的网页。例如,对于服务器上不存在的网页经常会返回此代码。
    如果您的网站上没有 robots.txt 文件,而您在 Google 网站管理员工具”诊断”标签的 robots.txt 页上看到此状态码,则这是正确的状态码。但是,如果您有 robots.txt 文件而又看到此状态码,则说明您的 robots.txt 文件可能命名错误或位于错误的位置(该文件应当位于顶级域,名为 robots.txt)。如果对于 Googlebot 抓取的网址看到此状态码(在”诊断”标签的 HTTP 错误页面上),则表示 Googlebot 跟随的可能是另一个页面的无效链接(是旧链接或输入有误的链接)。
  • 405(方法禁用)禁用请求中指定的方法。
  • 406(不接受)无法使用请求的内容特性响应请求的网页。
  • 407(需要代理授权)此状态码与 401(未授权)类似,但指定请求者应当授权使用代理。如果服务器返回此响应,还表示请求者应当使用代理。
  • 408(请求超时)服务器等候请求时发生超时。
  • 409(冲突)服务器在完成请求时发生冲突。服务器必须在响应中包含有关冲突的信息。服务器在响应与前一个请求相冲突的 PUT 请求时可能会返回此代码,以及两个请求的差异列表。
  • 410(已删除)如果请求的资源已永久删除,服务器就会返回此响应。该代码与 404(未找到)代码类似,但在资源以前存在而现在不存在的情况下,有时会用来替代404代码。如果资源已永久移动,您应使用301 指定资源的新位置。
  • 411(需要有效长度)服务器不接受不含有效内容长度标头字段的请求。
  • 412(未满足前提条件)服务器未满足请求者在请求中设置的其中一个前提条件。
  • 413(请求实体过大)服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
  • 414(请求的 URI 过长)请求的 URI(通常为网址)过长,服务器无法处理。
  • 415(不支持的媒体类型)请求的格式不受请求页面的支持。
  • 416(请求范围不符合要求)如果页面无法提供请求的范围,则服务器会返回此状态码。
  • 417(未满足期望值)服务器未满足”期望”请求标头字段的要求。

5xx:这些状态码表示服务器在处理请求时发生内部错误。这些错误可能是服务器本身的错误,而不是请求出错。

  • 500(服务器内部错误)服务器遇到错误,无法完成请求。
  • 501(尚未实施)服务器不具备完成请求的功能。例如,服务器无法识别请求方法时可能会返回此代码。
  • 502(错误网关)服务器作为网关或代理,从上游服务器收到无效响应。
  • 503(服务不可用)服务器目前无法使用(由于超载或停机维护)。通常,这只是暂时状态。
  • 504(网关超时)服务器作为网关或代理,但是没有及时从上游服务器收到请求。
  • 505(HTTP 版本不受支持)服务器不支持请求中所用的 HTTP 协议版本。

304 重定向

Etag:服务端资源唯一标识符(优先级高于Last Modified)

Last-modified:资源在服务器最后修改的时间(精确到秒) -> 所以需要唯一标识符

  • 第一次访问index.html(响应头) - 200 OK
  • 第二次访问 index.html(请求头) - 304 Not Modified
  • 第三次访问index.html(响应头) - 200 OK

Accept & Conetnt-Type

请求头:最希望接收到text/html, application/xhtml + xml,其次是application/xml,再其次是其他任意数据类型

响应头:text/html;charset=UTF-8,返回的资源类型与编码

Accept-Language & Content Language

Accept-Language浏览器支持语言是简体中文,其次是美国英语,再其次是其他形式的英语

Content Language 返回资源的语言类型

Accept-Encoding & Content-Encoding

浏览器可以接收的资源编码格式

服务器返回资源的编码格式(压缩格式,优化传输内容的大小)

浏览器缓存

把已请求闭关返回的WEB资源(HTML页面,图片,JS文件,CSS文件,数据等)复制成一个副本存储再浏览器的缓存中。

缓存的好处:

  • 减少网络带宽的消耗
  • 降低服务器压力
  • 减少网络延迟

Pragma:no-cache(http1.0)

指示浏览器忽略资源缓存副本,每次访问需要到服务器获取

Cache-Control

缓存控制(响应头)

  • no-cache:指示浏览器忽略资源缓存副本,强制到服务器获取资源(浏览器依旧缓存)
  • no-store:强制缓存再任何情况下都不要保留任何副本
  • max-age=31536000:指示缓存副本的有效时长,从请求时间开始到过期事件之间的秒数
  • public:表明响应可以被任何对象(包括:发送请求的客户端,代理服务器等)缓存
  • private:表面响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)

缓存过程

网络 - 图7

CONNECTION:KEEP-ALIVE

  • HTTP短连接与长连接
  • 所谓短连接,就是每次请求一个资源就建立连接,请求完成后连接立马关闭
  • 所谓长连接,只建立依次连接,多次资源请求都服用该连接,完成后关闭

短连接:

创建TCP连接 -> 请求资源 -> 响应资源 -> 断开连接

长连接:

网络 - 图8

  • 默认开启:Connection: keep-alive
  • 如需关闭:Connection: close

CONTENT-LENGTH

用于描述HTTP消息实体的传输长度

REFERER

是request header的一部分,当浏览器向web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的

好处:可以通过Referer分析不同渠道的流量分布,用户搜索的关键词

应用:防止资源盗链,服务器拉取资源之前判断referer是否是子级的域名或IP,如果不是就拦截,如果是则拉取资源

协议版本

HTTP协议版本

  • 0.9 Beta

    • 仅支持GET请求方式
    • 仅能请求访问HTML格式的资源
  • 1.0

    • 增加POST和HEAD请求方式
    • 支持多种数据格式的请求与访问
    • 支持cache缓存功能
    • 新增状态码,子字符集支持,内容编码等
    • 早期1.0不支持keep-alive长连接,只支持串行连接
    • 后期1.0增加Connection:keep-alive字段(非标准字段),开始支持长连接
  • 1.1

    • 增加持久连接(默认开启Connect: keep-alive)
    • 增加管道机制(支持多个请求同时发送)
    • 增加PUT/PATCH/OPTION/DELETE等请求方式
    • 增加Host字段(指定服务器域名)
    • 增加100状态码(Continue),支持只发送头信息
    • 增加身份认证机制
    • 支持传送内容的一部分和文件断点续传
    • 新增了24个错误状态码
  • 2.0

    • 增加双工模式(客户端同时发送多个请求,服务端同时处理多个请求)
    • 服务器推送(服务器会把客户端需要的资源一起推送到客户端,合适加载静态资源)
    • 二进制协议(头信息与数据体使用二进制进行传输)
    • 多工(先发送已处理好的部分,再响应其他请求,最后再解决没有处理好的部分)

四次挥手

关闭TCP连接的前奏

FIN:finish关闭连接 数据包

状态:

  • FIN-WAIT-1:等待原创TCP的连接中断请求,或先前的连接中断请求的确认
  • FIN-WAIT-2:从远程TCP等待连接中断请求
  • CLOSE-WAIT:等待从本地用户发来的连接中断请求
  • LAST-ACK:等待原来发向远程TCP的连接中断请求的确认
  • TIME-WAIT:等待足够的时间以确保远程TCP接收到连接中断请求的确认
  • CLOSED:没有任何连接状态

过程

网络 - 图9

  • 连接建立状态
  • 一次挥手:

    • 客户端 -> 服务器:发送连接关闭报文
    • 报文首部:FIN-1
    • 序列号 seq = u
    • 客户端状态为FIN-WAIT-1
  • 二次挥手:

    • 服务器 -> 客户端:收到连接关闭报文,并发送确认报文
    • 报文首部:ACK = 1 ack = u + 1(确认FIN)
    • 序列号 seq = v
    • 服务器状态为CLOSE-WAIT(连接半关闭状态)
    • 客户端进入等待2状态FIN-WAIT-2
  • 三次挥手:

    • 服务器 -> 客户端:确认数据已发送完毕后,继续发送连接关闭报文
    • 报文首部:FIN = 1 ACK = 1 ack = u + 1(确认上一次数据包)
    • 序列号 seq = w
    • 服务器进入最后确认状态LAST-ACK
  • 四次挥手:

    • 客户端 -> 服务器:发送接收确认报文
    • 报文首部:ACK = 1 ack = w + 1(确认上一次数据包)
    • 序列号 seq = u + 1
    • 进入时间等待状态TIME-WAIT
    • 服务器进入TCP关闭状态CLOSE

备注:

  • 连接半关闭状态,客户端没有数据要发送,但服务器如果还要发送数据,客户端依然需要接收
  • 在客户端进入FIN-WAIT-2状态期间,服务器会确认客户端所需要的数据是否真的发送完毕,如没有,则继续发送数据

为什么是四次挥手?

原因:

  • 第一次挥手的时候发送了FIN包,服务器接收到以后,表示客户端不再发送数据了,但还能接收数据。
  • 这时服务器先向客户端先发送确认包,而且确认自己是否还有数据没有发送给客户端,这个确认的阶段是CLOSE-WAIT
  • 所以在中止等待CLOSE-WAIT的开始和结束需要各发送一个包,状态开始时向客户端发送的包是确认收到来自客户端的FIN包
  • 状态结束时向客户端发送的是确认数据已经完整发送,所以是四次挥手。

同源策略

Same-Origin-Policy(SOP)

web浏览器只允许在两个页面有相同的源时,第一个页面的脚本访问第二个页面的数据

源(域名):协议 + 域名 + 端口

  • 同源:相同的协议 且 相同的域名 且 相同的端口
  • 不同源(跨域):不同的协议 或 不同的域名 或 不同的端口

跨域

跨域HTTP请求

不同源(跨域):

  • 不同的协议
  • 不同的域名
  • 不同的端口

实现跨域请求的方法:

  1. 服务器中转请求:客户端 -> 同源服务器 -> 非同源服务器
  2. 设置基础域名 + iframe(仅限于基础域名一致的情况)document.domain='xxx'
  3. window.name + iframe(一般传递简单的数据)
  4. postmessage + iframe
  5. Hash + iframe:利用url的hash值来传递数据(适用简单的字符串)
  6. CORS
  7. JSONP - JSON with Padding

关于window.name

  • 每个浏览器窗口都有一个全局变量window(包括iframe框架contentWindow)
  • 每个window对象都有一个name属性
  • 该窗口被关闭前(生命周期内),所有页面共享一个name属性并有读写的权限
  • 无论该窗口被关闭前,载入什么页面,都不会改变name值
  • 存储约为2M的字符串
  • 如果过父级窗口地址源和iframe的地址源不同,父级无法通过iframe.contentWindow.name获取值,但iframe内部不受该规则限制

    • 解决:先让iframe中的页面程序保存window.name,然后跳转与父级窗口同源的另一个页面, 父级页面可以从当前的iframe拿到该页面的window.name

关于postmessage 不常用的原因:

  • 伪造数据端漏洞
  • xss攻击
  • 兼容性问题

关于CROS:

跨域资源共享(Cross-origin resourse sharing)

  • 任意域名:header(Access-Control-Allow-Origin: *)
  • 单域名:header(Access-Control-Allow-Origin: http//test2.jsplusplus.com)
  • 多域名:

通知服务器在真正的请求中会采用哪种HTTP方法

header(‘Access-Control-Request-Methods: GET, POST’)

方法一:

网络 - 图10

方法二:

网络 - 图11

方法三:

网络 - 图12

准备index2.html, index3.html

  1. //index2.html
  2. <iframe src="index3.html" id="myIframe"></iframe>
  3. <script type="text/javascript">
  4. // 这里跟主页面不同源
  5. // //创建iframe
  6. // var iframe = document.createElement('iframe');
  7. // //引入网址
  8. // iframe.src = 'http://test.jsplusplus.com/index.html';
  9. // // 页面加载完毕
  10. // iframe.onload = function () {
  11. // console.log(iframe.contentWindow.name);
  12. // }
  13. // // 插入iframe到body
  14. // document.body.appendChild(iframe);
  15. // 标识
  16. var flag = false;
  17. var iframe = document.createElement('iframe');
  18. var getDatas = function () {
  19. if (flag) {
  20. //将同源的data拿出来
  21. var data = iframe.contentWindow.name;
  22. console.log(JSON.parse(data));
  23. } else {
  24. //如假
  25. flag = true;
  26. //跳转
  27. //这里跟index2.html同源
  28. //这里重新加载完毕后会重新执行index2.html里面的程序,然后走标识为true里的程序
  29. setTimeout(function () {
  30. iframe.contentWindow.location = 'index2.html';
  31. }, 500);
  32. }
  33. }
  34. //1.当页面加载后之后执行index3.html的程序请求ajax
  35. //2.index3.html的程序请求ajax后保存响应回来的data数据并保存到window.name
  36. //3.先打开flag标识,然后跳转页面到index2.html, 此时index2里可以拿到同源的data
  37. iframe.src = 'http://test.jsplusplus.com/index.html';
  38. //加载
  39. if (iframe.attachEvent) {
  40. iframe.attachEvent('onload', getDatas);
  41. } else {
  42. iframe.onload = getDatas;
  43. }
  44. document.body.appendChild(iframe);
  1. //index3.html
  2. //请求Ajax
  3. $.post('http://test.jsplusplus.com/get_course.php', {
  4. status: 1
  5. }, function (data) {
  6. // 响应的数据保持到name属性里
  7. window.name = JSON.stringify(data);
  8. })

方法四:

网络 - 图13

准备index1.html,index2.html

  1. //index1.html
  2. //请求Ajax
  3. $.post('http://test.jsplusplus.com/get_course.php', {
  4. status: 1
  5. }, function (data) {
  6. // 响应的数据保持到name属性里
  7. window.name = JSON.stringify(data);
  8. /**
  9. * otherWindow.postMessage(message, targetOrigin)
  10. * @otherWindow 接收方的引用
  11. * @message 要发送到接收方的数据
  12. * @targetOrigin 接收方的源,必须有监听message事件
  13. */
  14. window.parent.postMessage(JSON.stringify(data), 'http://test2.jsplusplus.com')
  15. })
  1. //index2.html
  2. //等待消息事件
  3. window.onmessage = function (e) {
  4. var e = e || window.event;
  5. console.log(JSON.parse(e.data));
  6. }

方法五:

网络 - 图14

iframe

准备index1.html, index2.html,index3.html

情况1:

index1.html

  1. <iframe src="index2.html" id="myIframe"></iframe>
  2. <script type="text/javascript">
  3. //获取节点
  4. var myIframe = document.getElementById('myIframe');
  5. //当引用页面加载完毕后
  6. myIframe.onload = function () {
  7. //打印iframe标签里的index2.html里面的所设置window.name属性的值
  8. //即iframe页面加载的窗口是: iframe
  9. //contentWindow相当于 浏览器对象 window
  10. console.log(myIframe.contentWindow.name); //iframeWindow
  11. }
  12. </script>

index2.html

  1. <iframe src="index3.html" id="myIframe"></iframe>
  2. <script type="text/javascript">
  3. //定义name属性
  4. window.name = 'iframeWindow';
  5. </script>

index1.html能获取index2.html里面的定义的属性的值

情况2:

index1.html

给本窗口定义name属性,值为mainWindow

  1. <iframe src="index2.html" id="myIframe"></iframe>
  2. <script type="text/javascript">
  3. //获取节点
  4. var myIframe = document.getElementById('myIframe');
  5. //当引用页面加载完毕后
  6. myIframe.onload = function () {
  7. //打印iframe标签里的index2.html里面的所设置window.name属性的值
  8. //即iframe页面加载的窗口是: iframe
  9. //contentWindow相当于 浏览器对象 window
  10. console.log(myIframe.contentWindow.name); //iframeWindow
  11. }
  12. window.name = 'mainWindow';
  13. </script>

index2.html

尝试访问index1.html里面的属性(子窗口访问父窗口),结果可以拿到父窗口的属性

  1. //定义name属性
  2. window.name = 'iframeWindow';
  3. //获取节点
  4. var myIframe = document.getElementById('myIframe');
  5. //当引用页面加载完毕后
  6. myIframe.onload = function () {
  7. //这里如何打印出index1.html主窗口name属性的值?
  8. //子窗口访问父窗口
  9. console.log(window.parent.name); //mainWindow
  10. }

说明window.name属性具有共享的特点

封装iframe

  1. var ajaxDomain = (function () {
  2. /**
  3. * 创建iframe
  4. * @param {*} frameId 标签里id属性
  5. * @param {*} frameUrl 标签里src属性
  6. */
  7. function createIframe(frameId, frameUrl) {
  8. //创建iframe
  9. var frame = document.createElement("iframe");
  10. frame.src = frameUrl;
  11. frame.id = frameId;
  12. frame.style.display = "none";
  13. //返回frame对象
  14. return frame;
  15. }
  16. return function (opt) {
  17. //声明基础域名
  18. document.domain = opt.basicDomain;
  19. var frame = createIframe(opt.frameId, opt.frameUrl);
  20. // 等待frame页面加载完毕
  21. frame.onload = function () {
  22. var $$ = document.getElementById(opt.frameId).contentWindow.$;
  23. $$.ajax({
  24. url: opt.url,
  25. type: opt.type,
  26. data: opt.data,
  27. success: opt.success,
  28. error: opt.error,
  29. });
  30. };
  31. document.appendChild(frame);
  32. };
  33. })();
  34. //调用
  35. ajaxDomain({
  36. baseDomain: "jsplusplus.com",
  37. frameUrl: "http://test.jsplusplus.com/index.html",
  38. url: "http://test.jsplusplus.com/get_courses1.php",
  39. type: "POST",
  40. data: {
  41. status: 1,
  42. },
  43. success: function (data) {
  44. console.log(data);
  45. },
  46. error: function () {
  47. console.log("error");
  48. },
  49. });

JSONP

JSON with Padding:跨域获取JSON数据的一种非官方的使用模式

  • JSON和JSONP不是一个类型
  • JSON是数据交换格式
  • JSONP是一种跨域获取JSON数据的交互技术
  • JSONP抓取的资源并不直接是JSON数据,而是带有JSON数据参数的函数执行
  • 客户端期望返回的是:{"name":"jack","age":"18"}
  • JSONP实际返回的是:callback({"name":"jack","age":"18"})

同源策略到底给谁走了后门?

  1. img的src引入不同源的图片资源
  2. link的herf引入不同源的样式文件资源
  3. iframe的src引入不同源的网页资源
  4. script的src引用不同源的脚本文件资源

示例

  1. <script type="text/javascript">
  2. function test1() {
  3. console.log(str);
  4. }
  5. function test2() {
  6. console.log(str);
  7. }
  8. function test3() {
  9. console.log(str);
  10. }
  11. </script>
  12. <script src="http://xxx.com/jsonp/jsonp.js?cb=test2" id="jsonpScript"></script>
  1. function getParams() {
  2. var path = document.getElementById('jsonpScript').scroll,
  3. callback = path.match(/cb=(.*)/)[1];
  4. switch (callback) {
  5. case 'test1':
  6. test1('test1');
  7. break;
  8. case 'test2':
  9. test1('test2');
  10. break;
  11. case 'test3':
  12. test1('test3');
  13. break;
  14. default:
  15. test1('test1');
  16. }
  17. }
  18. getParams();

ajax请求方式

  1. <script type="text/javascript">
  2. function test() {
  3. console.log(str);
  4. }
  5. </script>
  6. <script src="http://xxx.com/jsonp/jsonp.js?cb=test" id="jsonpScript"></script>
  1. $.ajax({
  2. url: 'http:xxx.com',
  3. type: 'post',
  4. data: {
  5. status: 1
  6. },
  7. success: function (data) {
  8. test(data);
  9. }
  10. })

script标签引入的文件不管是什么格式,只解析脚本,能运行就运行脚本,不能就报错

  1. //简易写法
  2. var oBtn = document.getElementById('btn');
  3. oBtn.onclick = function () {
  4. oScript = document.createElement('script');
  5. oScript.src = 'http://test.jsplusplus.com/jsonp/jsonp.php?cb=test';
  6. document.body.appendChild(oScript);
  7. document.body.removeChild(oScript);
  8. }
  9. function test(data) {
  10. console.log(data);
  11. }

案例:

  1. <div class="search-wrap">
  2. <div class="input-wrap">
  3. <input type="text" class="search-input J_searchInput" />
  4. </div>
  5. <div class="list-wrap">
  6. <ul class="wd-list J_wdList"></ul>
  7. </div>
  8. </div>
  9. <script type="text/html" id="J_listTpl">
  10. <li class="wd-item">
  11. <a href="https://www.baidu.com/s?wd={{wdLink}}" target="_blank" class="wd-lk">{{wd}}</a>
  12. </li>
  13. </script>
  1. //案例:百度联想词
  2. ;
  3. (function (doc) {
  4. var searchInput = doc.getElementsByClassName('J_searchInput')[0],
  5. wdList = doc.getElementsByClassName('J_wdList')[0],
  6. listWrap = wdList.parentNode,
  7. listTpl = doc.getElementById('J_listTpl').innerHTML;
  8. var init = function () {
  9. bindEvent();
  10. }
  11. function bindEvent() {
  12. searchInput.addEventListener('input', typeInput, false);
  13. }
  14. function typeInput() {
  15. var val = _trimSpace(this.value),
  16. len = val.length;
  17. if (len > 0) {
  18. getDatas(val, 'setDatas');
  19. } else {
  20. }
  21. }
  22. /**
  23. *
  24. * @param {*} value 输入的value值
  25. * @param {*} callbackName 回调函数名称
  26. */
  27. function getDatas(value, callbackName) {
  28. var oScript = doc.createElement('script');
  29. oScript.src = `https://www.baidu.com/sugrec?&prod=pc&wd=${value}&cb=${callbackName}`;
  30. doc.body.appendChild(oScript);
  31. doc.body.removeChild(oScript);
  32. }
  33. function _trimSpace(str) {
  34. //所有字符匹配0次或1次全局,替换为空
  35. return str.replace(/\s+/g, '');
  36. }
  37. window.setDatas = function (data) {
  38. renderList(data);
  39. }
  40. function renderList(data) {
  41. var list = '',
  42. data = data.g,
  43. len = data.length;
  44. if (len > 0) {
  45. data.forEach(function (elem) {
  46. list += listTpl.replace(/{{(.*?)}}/g, function (node, key) {
  47. return {
  48. wdLink: elem.q,
  49. wd: elem.q
  50. } [key]
  51. })
  52. wdList.innerHTML = list;
  53. listWrap.style.display = 'block';
  54. })
  55. } else {
  56. wdList.innerHTML = '';
  57. listWrap.style.display = 'none';
  58. }
  59. }
  60. init();
  61. })(document);

案例:请求ajax的方式

  1. //案例:百度联想词
  2. ;
  3. (function (doc) {
  4. var searchInput = doc.getElementsByClassName('J_searchInput')[0],
  5. wdList = doc.getElementsByClassName('J_wdList')[0],
  6. listWrap = wdList.parentNode,
  7. listTpl = doc.getElementById('J_listTpl').innerHTML;
  8. var init = function () {
  9. bindEvent();
  10. }
  11. function bindEvent() {
  12. searchInput.addEventListener('input', typeInput, false);
  13. }
  14. function typeInput() {
  15. var val = _trimSpace(this.value),
  16. len = val.length;
  17. if (len > 0) {
  18. getDatas(val);
  19. } else {
  20. }
  21. }
  22. /**
  23. *
  24. * @param {*} value 输入的value值
  25. */
  26. function getDatas(value) {
  27. $.ajax({
  28. url: `https://www.baidu.com/sugrec?&prod=pc&wd=${value}`,
  29. type: 'GET',
  30. dataType: 'JSONP',
  31. success: function (data) {
  32. renderList(data);
  33. }
  34. })
  35. }
  36. function _trimSpace(str) {
  37. //所有字符匹配0次或1次全局,替换为空
  38. return str.replace(/\s+/g, '');
  39. }
  40. function renderList(data) {
  41. var list = '',
  42. data = data.g,
  43. len = data.length;
  44. if (len > 0) {
  45. data.forEach(function (elem) {
  46. list += listTpl.replace(/{{(.*?)}}/g, function (node, key) {
  47. return {
  48. wdLink: elem.q,
  49. wd: elem.q
  50. } [key]
  51. })
  52. wdList.innerHTML = list;
  53. listWrap.style.display = 'block';
  54. })
  55. } else {
  56. wdList.innerHTML = '';
  57. listWrap.style.display = 'none';
  58. }
  59. }
  60. init();
  61. })(document);

cookie

http无状态协议

cookie字段属性解析

属性 描述
name 字段为一个cookie的名称
value 字段为一个cookie的值
domain 字段为可以访问此cookie的域名
path 字段为可以访问此cookie的页面路径
expires/Max-Age 字段为此cookie超时时间

增删改查封装

  1. /**
  2. * 封装cookie增删改查的函数
  3. */
  4. var manageCookies = {
  5. /**
  6. * 设置cookie属性及时间
  7. * 例如:document.cookie = 'name=xiaohong;max-age=1000'
  8. * 注意:只能逐条设置
  9. * @param {*} key 属性名
  10. * @param {*} value 属性值
  11. * @param {*} expTime 过期时间
  12. * @returns
  13. */
  14. set: function (key, value, expTime) {
  15. document.cookie = key + '=' + value + ';max-age=' + expTime;
  16. //实现链式调用
  17. return this;
  18. },
  19. /**
  20. * 删除cookie属性
  21. * 例如: document.cookie = 'name=xiaohong;max-age=-1'
  22. * @param {*} key 被删的属性
  23. */
  24. delete: function (key) {
  25. return this.set(key, '', -1);
  26. },
  27. /**
  28. * 查询cookie属性
  29. * 例如:document.cookie => 'hobby=basketball;sex=male;age=20'
  30. * 使用:get('hobby', function(data){console.log(data)})
  31. * @param {*} key
  32. * @param {*} cb
  33. * @returns
  34. */
  35. get: function (key, cb) {
  36. //将拿到的字符串用冒号分割成为数组
  37. //'hobby=basketball;sex=male;age=20'
  38. // => ['hobby=basketball','sex=male','age=20']
  39. var CookiesArray = document.cookie.split('; ');
  40. for (var i = 0; i < CookiesArray.length; i++) {
  41. var CookieItem = CookiesArray[i];
  42. //循环每一项并用等号分割
  43. //['hobby','basketball']
  44. //['sex','male']
  45. //['age','20']
  46. var CookieItemArray = CookieItem.split('=');
  47. if (CookieItemArray[0] == key) {
  48. cb(CookieItemArray[1]);
  49. return this;
  50. }
  51. }
  52. //如果没有cookie里面的属性报undefined
  53. cb(undefined);
  54. return this;
  55. }
  56. }

单点登陆

在不同源的一个系统下,任意一个站点程序做了登录操作,其他站点或程序同样处于登录状态机制,称为单点登录机制

持久登录

auth生成阶段:

  • 后端将用户名/密码加密(md5 + salt随机字符串) 生成身份识别码ident_code
  • 每次有登录操作后端都重新生成token身份令牌(32位A-Za-z0-9随机字符串)
  • 后端把处理好的身份识别码和身份令牌字符串拼接成授权auth字段auth = ident_code:token
  • username&password&ident_code&token字段都存放到数据库

auth验证阶段:

  • 后端分解auth为ident_codetoken字段
  • 后端到数据库查看ident_codetoken字段是否匹配
  • 后端对比时间是否超出timeout字段,若大于则过期
  • 如果验证通过进入登录,否则删除当前cookie

后端设置cookie

  1. setcookie('auth', ident_code:token, 过期时间, 有效路径, 有效域);

问题:为什么往数据库里存过期时间?

  • 答:如果客户端系统时间跟服务器时间不同,以服务器时间为准

验证流程

网络 - 图15

表单

基础认知

  1. <!-- 输入类型 -->
  2. <form action="server/b1.php" method="post">
  3. <input type="text" name="username" placeholder="用户名">
  4. <br />
  5. <input type="password" name="password" placeholder="密码">
  6. <br />
  7. <!-- 注意换行和空格 -->
  8. <textarea name="intro"></textarea>
  9. <br />
  10. <!-- 选项类型 -->
  11. <input type="radio" name="sex" value="male" checked="checked">
  12. <input type="radio" name="sex" value="female">
  13. <br />
  14. <input type="checkbox" name="hobby" value="fb">足球
  15. <input type="checkbox" name="hobby" value="bb">篮球
  16. <input type="checkbox" name="hobby" value="golf">高尔夫球
  17. <br />
  18. <select name="occipation">
  19. <option value="fe">前端</option>
  20. <option value="be">后端</option>
  21. </select>
  22. <br />
  23. <!-- 按钮类型 -->
  24. <input type="submit" value="提交">
  25. <input type="reset" value="重置">
  26. </form>

以上存在语义化不明确的情况

  1. <!-- button -->
  2. <button type="submit">提交</button>
  3. <button type="reset">重置</button>

阻止默认表单提交

同步提交的坏处是跳转页面,导致前端无法验证表单数据的合法性

异步提交表单

  1. <form action="server/b1.php" method="post" onsubmit="return false">
  1. <form action="server/b1.php" method="post" onsubmit="return submitForm()">

关于onsubmit属性,默认return指定的函数后再return空的onsubmit=""

也可以使用e.preventDefault()阻止默认提交

文件上传

问题:文件和数据有什么区别?

数据是字符串,文件是文件

  • application/x-www-form-urlencoded:把表单填写的数据键值对化,
  • enctype="application/x-www-form-urlencoded":用数据格式进行编码
  • form表单enctype属性默认值为application/x-www-form-urlencoded

上传文件时也是用该编码格式进行上传,例如:filename=123&file=1.jpg,上传文件并不可以纯文本的形式上传,文件需要用二进制的方式碎片化上传

  • enctype="multipart/form-data":将上传的文件类型转为二进制类型
  • multiple:多选

同步上传:

  • name="file[]"

FormData

FormData表单数据构造函数,适用JS动态创建form表单

  1. var fd = new FormData();

append()方法:增加一行表单项数据

  • 参数1:数据的名称
  • 参数2:名称对应的值
  1. fd.append('Username', oUsername.value);
  2. fd.append('Password', oPassword.value);
  3. //output
  4. FormData: {}

get()方法:接收字符串键名

  1. fd.get('Username');
  2. fd.get('Password');
  3. //output
  4. username: zhangsan
  5. password: 123

set()方法:更改对应属性的值

  1. fd.set('Username', 'lisi');
  2. //output
  3. username: lisi

has()方法:返回是否存在该属性的布尔值

  1. fd.has('Password');
  2. //output
  3. false

delete()方法:删除指定属性

  1. fd.delete('Password');
  2. //output
  3. null

Q&A

问题1:减少http请求的方法

从url回车 到 页面呈现有什么步骤?

  1. url输入回车?
  2. dns解析url变成相应代理服务器的IP地址
  3. 浏览器网络向相应服务器发起TCP/IP连接请求
  4. 三次握手建立TCP/IP连接
  5. 浏览器网络发起http请求
  6. 响应过程
  7. 下载HTML资源
  8. 解析HTML
  9. 遇到HTML里的资源,再次发起HTTP请求,下载资源
  10. 时间线
  11. 呈现页面

最耗费时间的是资源请求,降低HTTP请求的必要性:

  • 能做雪碧图就做雪碧图
  • base64编码图片
  • 合并脚本与样式表代码
  • 配置多个域名 CDN加速服务
  • 尽量使用浏览器的缓存机制
  • img / map