网络
请求流程
浏览器请求一个网页的流程:
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包含了:
协议名称 + 主机名称 + 端口号 + 路径 + 文件 + 查询所需字符串
http:// jsplusplus.com:80/ Index/index.html ?a=1&b=2 #d
注:https默认端口号443 http默认端口号80
如何找一个人?
- 家庭住址 -> URL ->
http://jsplusplus.com:80/ Index/index.html?a=1&b=2#d - 姓名 + 身份证号 -> 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解析过程

解析顺序:
- 根
- .com
- jspp域名
- 二级域名
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:代表一个打开的连接,数据可以传送给用户(数据建立了哈,我跟你说一下)
三次握手

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
报文如何发送

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

请求方式
报文请求方式:
- 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):

关于管道化持续连接:
把所有请求放到发送队列里,不等响应,一个一个发送请求的同时接收响应的响应
弊端:一旦出现连接问题,请求将被清空,重新再来,不合适更改数据

状态码
| 状态码 | 描述 |
|---|---|
| 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:表面响应只能被单个用户缓存,不能作为共享缓存(即代理服务器不能缓存它)
缓存过程

CONNECTION:KEEP-ALIVE
- HTTP短连接与长连接
- 所谓短连接,就是每次请求一个资源就建立连接,请求完成后连接立马关闭
- 所谓长连接,只建立依次连接,多次资源请求都服用该连接,完成后关闭
短连接:
创建TCP连接 -> 请求资源 -> 响应资源 -> 断开连接
长连接:

- 默认开启: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:没有任何连接状态
过程

- 连接建立状态
一次挥手:
- 客户端 -> 服务器:发送连接关闭报文
- 报文首部: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请求
不同源(跨域):
- 不同的协议
- 不同的域名
- 不同的端口
实现跨域请求的方法:
- 服务器中转请求:客户端 -> 同源服务器 -> 非同源服务器
- 设置基础域名 + iframe(仅限于基础域名一致的情况)
document.domain='xxx' window.name+ iframe(一般传递简单的数据)- postmessage + iframe
- Hash + iframe:利用url的hash值来传递数据(适用简单的字符串)
- CORS
- 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
- 解决:先让iframe中的页面程序保存
关于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’)
方法一:

方法二:

方法三:

准备index2.html, index3.html
//index2.html<iframe src="index3.html" id="myIframe"></iframe><script type="text/javascript">// 这里跟主页面不同源// //创建iframe// var iframe = document.createElement('iframe');// //引入网址// iframe.src = 'http://test.jsplusplus.com/index.html';// // 页面加载完毕// iframe.onload = function () {// console.log(iframe.contentWindow.name);// }// // 插入iframe到body// document.body.appendChild(iframe);// 标识var flag = false;var iframe = document.createElement('iframe');var getDatas = function () {if (flag) {//将同源的data拿出来var data = iframe.contentWindow.name;console.log(JSON.parse(data));} else {//如假flag = true;//跳转//这里跟index2.html同源//这里重新加载完毕后会重新执行index2.html里面的程序,然后走标识为true里的程序setTimeout(function () {iframe.contentWindow.location = 'index2.html';}, 500);}}//1.当页面加载后之后执行index3.html的程序请求ajax//2.index3.html的程序请求ajax后保存响应回来的data数据并保存到window.name//3.先打开flag标识,然后跳转页面到index2.html, 此时index2里可以拿到同源的dataiframe.src = 'http://test.jsplusplus.com/index.html';//加载if (iframe.attachEvent) {iframe.attachEvent('onload', getDatas);} else {iframe.onload = getDatas;}document.body.appendChild(iframe);
//index3.html//请求Ajax$.post('http://test.jsplusplus.com/get_course.php', {status: 1}, function (data) {// 响应的数据保持到name属性里window.name = JSON.stringify(data);})
方法四:

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

iframe
准备index1.html, index2.html,index3.html
情况1:
index1.html
<iframe src="index2.html" id="myIframe"></iframe><script type="text/javascript">//获取节点var myIframe = document.getElementById('myIframe');//当引用页面加载完毕后myIframe.onload = function () {//打印iframe标签里的index2.html里面的所设置window.name属性的值//即iframe页面加载的窗口是: iframe//contentWindow相当于 浏览器对象 windowconsole.log(myIframe.contentWindow.name); //iframeWindow}</script>
index2.html
<iframe src="index3.html" id="myIframe"></iframe><script type="text/javascript">//定义name属性window.name = 'iframeWindow';</script>
index1.html能获取index2.html里面的定义的属性的值
情况2:
index1.html
给本窗口定义name属性,值为mainWindow
<iframe src="index2.html" id="myIframe"></iframe><script type="text/javascript">//获取节点var myIframe = document.getElementById('myIframe');//当引用页面加载完毕后myIframe.onload = function () {//打印iframe标签里的index2.html里面的所设置window.name属性的值//即iframe页面加载的窗口是: iframe//contentWindow相当于 浏览器对象 windowconsole.log(myIframe.contentWindow.name); //iframeWindow}window.name = 'mainWindow';</script>
index2.html
尝试访问index1.html里面的属性(子窗口访问父窗口),结果可以拿到父窗口的属性
//定义name属性window.name = 'iframeWindow';//获取节点var myIframe = document.getElementById('myIframe');//当引用页面加载完毕后myIframe.onload = function () {//这里如何打印出index1.html主窗口name属性的值?//子窗口访问父窗口console.log(window.parent.name); //mainWindow}
说明window.name属性具有共享的特点
封装iframe
var ajaxDomain = (function () {/*** 创建iframe* @param {*} frameId 标签里id属性* @param {*} frameUrl 标签里src属性*/function createIframe(frameId, frameUrl) {//创建iframevar frame = document.createElement("iframe");frame.src = frameUrl;frame.id = frameId;frame.style.display = "none";//返回frame对象return frame;}return function (opt) {//声明基础域名document.domain = opt.basicDomain;var frame = createIframe(opt.frameId, opt.frameUrl);// 等待frame页面加载完毕frame.onload = function () {var $$ = document.getElementById(opt.frameId).contentWindow.$;$$.ajax({url: opt.url,type: opt.type,data: opt.data,success: opt.success,error: opt.error,});};document.appendChild(frame);};})();//调用ajaxDomain({baseDomain: "jsplusplus.com",frameUrl: "http://test.jsplusplus.com/index.html",url: "http://test.jsplusplus.com/get_courses1.php",type: "POST",data: {status: 1,},success: function (data) {console.log(data);},error: function () {console.log("error");},});
JSONP
JSON with Padding:跨域获取JSON数据的一种非官方的使用模式
- JSON和JSONP不是一个类型
- JSON是数据交换格式
- JSONP是一种跨域获取JSON数据的交互技术
- JSONP抓取的资源并不直接是JSON数据,而是带有JSON数据参数的函数执行
- 客户端期望返回的是:
{"name":"jack","age":"18"} - JSONP实际返回的是:
callback({"name":"jack","age":"18"})
同源策略到底给谁走了后门?
- img的src引入不同源的图片资源
- link的herf引入不同源的样式文件资源
- iframe的src引入不同源的网页资源
- script的src引用不同源的脚本文件资源
示例
<script type="text/javascript">function test1() {console.log(str);}function test2() {console.log(str);}function test3() {console.log(str);}</script><script src="http://xxx.com/jsonp/jsonp.js?cb=test2" id="jsonpScript"></script>
function getParams() {var path = document.getElementById('jsonpScript').scroll,callback = path.match(/cb=(.*)/)[1];switch (callback) {case 'test1':test1('test1');break;case 'test2':test1('test2');break;case 'test3':test1('test3');break;default:test1('test1');}}getParams();
ajax请求方式
<script type="text/javascript">function test() {console.log(str);}</script><script src="http://xxx.com/jsonp/jsonp.js?cb=test" id="jsonpScript"></script>
$.ajax({url: 'http:xxx.com',type: 'post',data: {status: 1},success: function (data) {test(data);}})
script标签引入的文件不管是什么格式,只解析脚本,能运行就运行脚本,不能就报错
//简易写法var oBtn = document.getElementById('btn');oBtn.onclick = function () {oScript = document.createElement('script');oScript.src = 'http://test.jsplusplus.com/jsonp/jsonp.php?cb=test';document.body.appendChild(oScript);document.body.removeChild(oScript);}function test(data) {console.log(data);}
案例:
<div class="search-wrap"><div class="input-wrap"><input type="text" class="search-input J_searchInput" /></div><div class="list-wrap"><ul class="wd-list J_wdList"></ul></div></div><script type="text/html" id="J_listTpl"><li class="wd-item"><a href="https://www.baidu.com/s?wd={{wdLink}}" target="_blank" class="wd-lk">{{wd}}</a></li></script>
//案例:百度联想词;(function (doc) {var searchInput = doc.getElementsByClassName('J_searchInput')[0],wdList = doc.getElementsByClassName('J_wdList')[0],listWrap = wdList.parentNode,listTpl = doc.getElementById('J_listTpl').innerHTML;var init = function () {bindEvent();}function bindEvent() {searchInput.addEventListener('input', typeInput, false);}function typeInput() {var val = _trimSpace(this.value),len = val.length;if (len > 0) {getDatas(val, 'setDatas');} else {}}/**** @param {*} value 输入的value值* @param {*} callbackName 回调函数名称*/function getDatas(value, callbackName) {var oScript = doc.createElement('script');oScript.src = `https://www.baidu.com/sugrec?&prod=pc&wd=${value}&cb=${callbackName}`;doc.body.appendChild(oScript);doc.body.removeChild(oScript);}function _trimSpace(str) {//所有字符匹配0次或1次全局,替换为空return str.replace(/\s+/g, '');}window.setDatas = function (data) {renderList(data);}function renderList(data) {var list = '',data = data.g,len = data.length;if (len > 0) {data.forEach(function (elem) {list += listTpl.replace(/{{(.*?)}}/g, function (node, key) {return {wdLink: elem.q,wd: elem.q} [key]})wdList.innerHTML = list;listWrap.style.display = 'block';})} else {wdList.innerHTML = '';listWrap.style.display = 'none';}}init();})(document);
案例:请求ajax的方式
//案例:百度联想词;(function (doc) {var searchInput = doc.getElementsByClassName('J_searchInput')[0],wdList = doc.getElementsByClassName('J_wdList')[0],listWrap = wdList.parentNode,listTpl = doc.getElementById('J_listTpl').innerHTML;var init = function () {bindEvent();}function bindEvent() {searchInput.addEventListener('input', typeInput, false);}function typeInput() {var val = _trimSpace(this.value),len = val.length;if (len > 0) {getDatas(val);} else {}}/**** @param {*} value 输入的value值*/function getDatas(value) {$.ajax({url: `https://www.baidu.com/sugrec?&prod=pc&wd=${value}`,type: 'GET',dataType: 'JSONP',success: function (data) {renderList(data);}})}function _trimSpace(str) {//所有字符匹配0次或1次全局,替换为空return str.replace(/\s+/g, '');}function renderList(data) {var list = '',data = data.g,len = data.length;if (len > 0) {data.forEach(function (elem) {list += listTpl.replace(/{{(.*?)}}/g, function (node, key) {return {wdLink: elem.q,wd: elem.q} [key]})wdList.innerHTML = list;listWrap.style.display = 'block';})} else {wdList.innerHTML = '';listWrap.style.display = 'none';}}init();})(document);
cookie
http无状态协议
cookie字段属性解析
| 属性 | 描述 |
|---|---|
| name | 字段为一个cookie的名称 |
| value | 字段为一个cookie的值 |
| domain | 字段为可以访问此cookie的域名 |
| path | 字段为可以访问此cookie的页面路径 |
| expires/Max-Age | 字段为此cookie超时时间 |
增删改查封装
/*** 封装cookie增删改查的函数*/var manageCookies = {/*** 设置cookie属性及时间* 例如:document.cookie = 'name=xiaohong;max-age=1000'* 注意:只能逐条设置* @param {*} key 属性名* @param {*} value 属性值* @param {*} expTime 过期时间* @returns*/set: function (key, value, expTime) {document.cookie = key + '=' + value + ';max-age=' + expTime;//实现链式调用return this;},/*** 删除cookie属性* 例如: document.cookie = 'name=xiaohong;max-age=-1'* @param {*} key 被删的属性*/delete: function (key) {return this.set(key, '', -1);},/*** 查询cookie属性* 例如:document.cookie => 'hobby=basketball;sex=male;age=20'* 使用:get('hobby', function(data){console.log(data)})* @param {*} key* @param {*} cb* @returns*/get: function (key, cb) {//将拿到的字符串用冒号分割成为数组//'hobby=basketball;sex=male;age=20'// => ['hobby=basketball','sex=male','age=20']var CookiesArray = document.cookie.split('; ');for (var i = 0; i < CookiesArray.length; i++) {var CookieItem = CookiesArray[i];//循环每一项并用等号分割//['hobby','basketball']//['sex','male']//['age','20']var CookieItemArray = CookieItem.split('=');if (CookieItemArray[0] == key) {cb(CookieItemArray[1]);return this;}}//如果没有cookie里面的属性报undefinedcb(undefined);return this;}}
单点登陆
在不同源的一个系统下,任意一个站点程序做了登录操作,其他站点或程序同样处于登录状态机制,称为单点登录机制
持久登录
auth生成阶段:
- 后端将用户名/密码加密(md5 + salt随机字符串) 生成身份识别码
ident_code - 每次有登录操作后端都重新生成
token身份令牌(32位A-Za-z0-9随机字符串) - 后端把处理好的身份识别码和身份令牌字符串拼接成授权auth字段
auth = ident_code:token username&password&ident_code&token字段都存放到数据库
auth验证阶段:
- 后端分解auth为
ident_code和token字段 - 后端到数据库查看
ident_code和token字段是否匹配 - 后端对比时间是否超出timeout字段,若大于则过期
- 如果验证通过进入登录,否则删除当前cookie
后端设置cookie
setcookie('auth', ident_code:token, 过期时间, 有效路径, 有效域);
问题:为什么往数据库里存过期时间?
- 答:如果客户端系统时间跟服务器时间不同,以服务器时间为准
验证流程

表单
基础认知
<!-- 输入类型 --><form action="server/b1.php" method="post"><input type="text" name="username" placeholder="用户名"><br /><input type="password" name="password" placeholder="密码"><br /><!-- 注意换行和空格 --><textarea name="intro"></textarea><br /><!-- 选项类型 --><input type="radio" name="sex" value="male" checked="checked">男<input type="radio" name="sex" value="female">女<br /><input type="checkbox" name="hobby" value="fb">足球<input type="checkbox" name="hobby" value="bb">篮球<input type="checkbox" name="hobby" value="golf">高尔夫球<br /><select name="occipation"><option value="fe">前端</option><option value="be">后端</option></select><br /><!-- 按钮类型 --><input type="submit" value="提交"><input type="reset" value="重置"></form>
以上存在语义化不明确的情况
<!-- button --><button type="submit">提交</button><button type="reset">重置</button>
阻止默认表单提交
同步提交的坏处是跳转页面,导致前端无法验证表单数据的合法性
异步提交表单
<form action="server/b1.php" method="post" onsubmit="return false">
<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表单
var fd = new FormData();
append()方法:增加一行表单项数据
- 参数1:数据的名称
- 参数2:名称对应的值
fd.append('Username', oUsername.value);fd.append('Password', oPassword.value);//outputFormData: {}
get()方法:接收字符串键名
fd.get('Username');fd.get('Password');//outputusername: zhangsanpassword: 123
set()方法:更改对应属性的值
fd.set('Username', 'lisi');//outputusername: lisi
has()方法:返回是否存在该属性的布尔值
fd.has('Password');//outputfalse
delete()方法:删除指定属性
fd.delete('Password');//outputnull
Q&A
问题1:减少http请求的方法
从url回车 到 页面呈现有什么步骤?
- url输入回车?
- dns解析url变成相应代理服务器的IP地址
- 浏览器网络向相应服务器发起TCP/IP连接请求
- 三次握手建立TCP/IP连接
- 浏览器网络发起http请求
- 响应过程
- 下载HTML资源
- 解析HTML
- 遇到HTML里的资源,再次发起HTTP请求,下载资源
- 时间线
- 呈现页面
最耗费时间的是资源请求,降低HTTP请求的必要性:
- 能做雪碧图就做雪碧图
- base64编码图片
- 合并脚本与样式表代码
- 配置多个域名 CDN加速服务
- 尽量使用浏览器的缓存机制
- img / map
