主题
网络基础类
1. 跨域
很多种⽅法,但万变不离其宗,都是为了搞定同源策略 。重用的有 jsonp
、 iframe
、 cors
、 img
、HTML5 postMessage
等等 。其中用到 html
标签进行跨域的原理就是 html
不受同源策略影响 。但只是接受 Get
的请求⽅式, 这个得清楚。
延伸 1: img
iframe
script
来发送跨域请求有什么优缺点?
iframe
- 优点:跨域完毕之后
DOM
操作和互相之间的JavaScript
调用都是没有问题的 - 缺点:1.若结果要以
URL
参数传递, 这就意味着在结果数据量很大的时候需要分割传递,巨烦 。2.还有⼀个是iframe
本身带来的, 母页面和iframe
本身的交互本身就有安全性限制。
script
- 优点:可以直接返回
json
格式的数据, 方便处理 - 缺点:只接受
GET
请求方式
- 图片 ping
- 优点:可以访问任何
url
,⼀ 般用来进行点击追踪,做页面分析常用的方法 - 缺点:不能访问响应文本, 只能监听是否响应
延伸 2:配合 webpack
进行反向代理?
webpack
在 devServer
选项里面提供了⼀个 proxy
的参数供开发⼈员进行反向代理
js
'/api': {
target: 'http://www.example.com', // your target host
changeOrigin: true, // needed for virtual hosted sites
pathRewrite: {
'^/api': '' // rewrite path
}
},
然后再配合 http-proxy-middleware
插件对 api
请求地址进行代理
js
const express = require("express");
const proxy = require("http-proxy-middleware");
// proxy api requests
const exampleProxy = proxy(options); // 这里的 options
// mount `exampleProxy` in web server
const app = express();
app.use("/api", exampleProxy);
app.listen(3000);
然后再用 nginx
把允许跨域的源地址添加到报头里面即可
说到 nginx
, 可以再谈谈 CORS
配置,大致如下
js
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'DNT, X-Mx-ReqToken, Keep-Ali
add_header 'Access-Control-Max-Age' 86400;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 200;
}
}
2. http 无状态无连接
http
协议对于事务处理没有记忆能⼒- 对同⼀个
url
请求没有上下文关系 - 每次的请求都是独立的, 它的执行情况和结果与前面的请求和之后的请求是无直接关系的, 它不会受前面的请求应答情况直接影响,也不会直接影响后面的请求应答情况
- 服务器中没有保存客户端的状态,客户端必须每次带上自己的状态去请求服务器
- ⼈生若只如初见,请求过的资源下⼀次会继续进行请求
http 协议无状态中的 状态 到底指的是什么?!
- 【状态】 的含义就是:客户端和服务器在某次会话中产生的数据
- 那么对应的 【无状态】 就意味着:这些数据不会被保留
- 通过增加
cookie
和session
机制,现在的网络请求其实是有状态的 - 在没有状态的
http
协议下, 服务器也⼀定会保留你每次网络请求对数据的修改,但这跟保留每次访问的数据是不⼀样的,保留的只是会话产生的结果, 而没有保留会话
3. http-cache:就是 http 缓存
- 首先得明确
http
缓存的好处
- 减少了冗余的数据传输,减少网费
- 减少服务器端的压⼒
Web
缓存能够减少延迟与网络阻塞, 进而减少显示某个资源所用的时间- 加快客户端加载网页的速度
- 常见
http
缓存的类型
- 私有缓存 (⼀般为本地浏览器缓存)
- 代理缓存
- 然后谈谈本地缓存
本地缓存是指浏览器请求资源时命中了浏览器本地的缓存资源, 浏览器并不会发送真正的请求给服务器了 。它的执⾏过程是
- 第⼀次浏览器发送请求给服务器时,此时浏览器还没有本地缓存副本, 服务器返回资源给浏览器, 响应码是
200 OK
, 浏览器收到资源后, 把资源和对应的响应头⼀起缓存下来 - 第⼆次浏览器准备发送请求给服务器时候, 浏览器会先检查上⼀次服务端返回的响应头信息中的
Cache-Control
, 它的值是⼀个相对值, 单位为秒,表示资源在客户端缓存的最大有效期, 过期时间为第⼀次请求的时间减去Cache-Control
的值, 过期时间跟当前的请求时间比较, 如果本地缓存资源没过期,那么命中缓存,不再请求服务器 - 如果没有命中, 浏览器就会把请求发送给服务器, 进⼊缓存协商阶段。
与本地缓存相关的头有: Cache-Control
、 Expires
, Cache-Control
有多个可选值代表不同的意义, 而 Expires
就是⼀个日期格式的绝对值。
Cache-Control
Cache-Control
是 HTPP
缓存策略中最重要的头, 它是 HTTP/1.1
中出现的, 它由如下⼏个值
no-cache
:不使用本地缓存 。需要使用缓存协商, 先与服务器确认返回的响应是否被更改, 如果之前的响应中存在ETag
,那么请求的时候会与服务端验证, 如果资源未被更改,则可以避免重新下载no-store
:直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送⼀个请求,每次都会下载完整的资源public
:可以被所有的用户缓存, 包括终端用户和CDN
等中间代理服务器 。private
:只能被终端用户的浏览器缓存,不允许CDN
等中继缓存服务器对其缓存。max-age
:从当前请求开始, 允许获取的响应被重用的最长时间 (秒) 。
例如: Cache-Control: public, max-age=1000 表示资源可以被所有用户以及代理服务器缓存, 最长时间为 1000 秒。
Expires
Expires
是 HTTP/1.0
出现的头信息, 同样是用于决定本地缓存策略的头,它是⼀个绝对时间, 时间格式是如 Mon, 10 Jun 2015 21:31:12 GMT
, 只要发送请求时间是在 Expires
之前,那么本地缓存始终有效, 否则就会去服务器发送请求获取新的资源 。如果同时出现 Cache-Control:max-age
和 Expires
,那么 max-age
优先级更高 。他们可以这样组合使用
js
Cache-Control: public
Expires: Wed, Jan 10 2018 00:27:04 GMT
所谓的缓存协商
当第⼀次请求时服务器返回的响应头中存在以下情况时
- 没有
Cache-Control
和Expires
Cache-Control
和Expires
过期了Cache-Control
的属性设置为no-cache
时
那么浏览器第⼆次请求时就会与服务器进行协商,询问浏览器中的缓存资源是不是旧版本, 需不需要更新,此时, 服务器就会做出判断, 如果缓存和服务端资源的最新版本是⼀致的,那么就⽆需再次下载该资源, 服务端直接返回 304 Not Modified
状态码, 如果服务器发现浏览器中的缓存已经是旧版本了,那么服务器就会把最新资源的完整内容返回给浏览器,状态码就是 200 Ok
,那么服务端是根据什么来判断浏览器的缓存是不是最新的呢?其实是根据 HTTP
的另外两组头信息,分别是: Last-Modified/If-Modified-Since
与 ETag/If-None-Match
。
Last-Modified
与 If-Modified-Since
- 浏览器第⼀次请求资源时, 服务器会把资源的最新修改时间
Last-Modified:Thu, 29 Dec 2011 18:23:55 GMT
放在响应头中返回给浏览器 - 第⼆次请求时, 浏览器就会把上⼀次服务器返回的修改时间放在请求头
If-Modified-Since:Thu, 29 Dec 2011 18:23:55
发送给服务器, 服务器就会拿这个时间跟服务器上的资源的最新修改时间进行对比
如果两者相等或者大于服务器上的最新修改时间,那么表示浏览器的缓存是有效的,此时缓存会命中, 服务器就不再返回内容给浏览器了, 同时 Last-Modified
头也不会返回, 因为资源没被修改, 返回了也没什么意义 。如果没命中缓存则最新修改的资源连同 Last-Modified
头⼀起返回
第⼀次请求返回的响应头
Cache-Control:max-age=3600 Expires: Fri, Jan 12 2018 00:27:04 GMT Last-Modified: Wed, Jan 10 2018 00:27:04 GMT
第⼆次请求的请求头信息
If-Modified-Since: Wed, Jan 10 2018 00:27:04 GMT
这组头信息是基于资源的修改时间来判断资源有没有更新, 另⼀种方式就是根据资源的内容来判断,就是接下来要讨论的 ETag
与 If-None-Match
ETag
与 If-None-Match
ETag/If-None-Match
与 Last-Modified/If-Modified-Since
的流程其实是类似的, 唯⼀的区别是它基于资源的内容的摘要信息 ( 比如 MD5 hash
) 来判断
浏览器发送第⼆次请求时,会把第⼀次的响应头信息 ETag
的值放在 If-None-Match
的请求头中发送到服务器,与最新的资源的摘要信息对比, 如果相等, 取浏览器缓存, 否则内容有更新, 最新的资源连同最新的摘要信息返回 。用 ETag
的好处是如果因为某种原因到时资源的修改时间没改变,那么用 ETag
就能区分资源是不是有被更新。
第⼀次请求返回的响应头:
Cache-Control: public, max-age=31536000 ETag: "15f0fff99ed5aae4edffdd6496d7131f"
第⼆次请求的请求头信息:
If-None-Match: "15f0fff99ed5aae4edffdd6496d7131f"
4. cookie 和 session
session
: 是⼀个抽象概念, 开发者为了实现中断和继续等操作,将user agent
和server
之间⼀对⼀的交互,抽象为“会话”, 进而衍生出“会话状态”,也就是session
的概念cookie
:它是⼀个世纪存在的东⻄,http
协议中定义在header
中的字段, 可以认为是session
的⼀种后端无状态实现
现在我们常说的 session
, 是为了绕开 cookie
的各种限制, 通常借助 cookie
本身和后端存储实现的,⼀ 种更高级的会话状态实现
session
的常⻅实现要借助 cookie
来发送 sessionID
5. 安全问题, 如 XSS 和 CSRF
XSS
:跨站脚本攻击, 是⼀种网站应用程序的安全漏洞攻击, 是代码注⼊的⼀种 。常⻅方式是将恶意代码注⼊合法代码里隐藏起来, 再诱发恶意代码,从而进⾏各种各样的非法活动防范:记住⼀点“所有用户输⼊都是不可信的”,所以得做输⼊过滤和转义
CSRF
:跨站请求伪造,也称XSRF
, 是⼀种挟制用户在当前已登录的 Web 应用程序上执⾏非本意的操作的攻击方法 。与XSS
相比,XSS
利用的是用户对指定网站的信任,CSRF
利用的是网站对用户网页浏览器的信任防范:用户操作验证 (验证码), 额外验证机制 (
token
使用) 等