简单请求和非简单请求
- 简单请求条件
- 请求方法为
GET
、POST
和HEAD
- 除
Accept
、Accept-Language
、Content-Language
和Content-Type
外无自定义头信息 - Content-Type为
text/plain
、multipart/form-data
和application/x-www-form-urlencoded
- 请求中的任意XMLHttpRequestUpload 对象均没有注册任何事件监听器;XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问
- 请求中没有使用 ReadableStream 对象
- 请求方法为
- 非简单请求(复杂请求)
- 不满足简单请求既为非简单请求
跨域
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域。跨域会导致以下问题:
- 无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
- 无法接触非同源网页的 DOM
- 无法向非同源地址发送 AJAX 请求
解决方法
- 设置相同的document.domain(仅限主域相同,子域不同),可实现访问子窗口
- 使用window.postMessage()实现跨窗口(包括不同域)传递数据
// 父窗口打开一个窗口
var openWindow = window.open('http://test2.com', 'title');
// 第一个参数代表发送的内容,第二个参数代表接收消息窗口的url
openWindow.postMessage('Nice to meet you!', 'http://test2.com');
// 子窗口监听message事件
window.addEventListener('message', function (e) {
console.log(e.source); // e.source 发送消息的窗口
console.log(e.origin); // e.origin 消息发向的网址
console.log(e.data); // e.data 发送的消息
}, false);
- JSONP请求,实现跨域请求
- CORS(跨域资源分享)参考链接
- 简单请求下
- 请求和普通请求一样
- 响应头必须包含
Access-Control-Allow-Origin
- 当需要带cookie时,请求时要设置
xhr.withCredentials = true
,响应头必须包含Access-Control-Allow-Credentials
且值为true(如果不带cookie则必须忽略该属性,不能设为false) - 可选属性
Access-Control-Expose-Headers
用于规定xhr.getResponseHeader()
所能获取的信息
- 复杂请求下
- 复杂请求时,浏览器会以OPTIONS的方式发起一个预请求,请求头部包含
- Access-Control-Request-Method:该项内容是实际请求的种类,可以是GET、POST之类的简单请求,也可以是PUT、DELETE等等。
- Access-Control-Request-Headers:该项是一个以逗号分隔的列表,当中是复杂请求所使用的头部。
- 响应头包含
- Access-Control-Allow-Origin(必含) – 和简单请求一样的,必须包含一个域。
- Access-Control-Allow-Methods(必含) – 这是对预请求当中Access-Control-Request-Method的回复,这一回复将是一个以逗号分隔的列表。
- Access-Control-Allow-Headers(当预请求中包含Access-Control-Request-Headers时必须包含) – 这是对预请求当中Access-Control-Request-Headers的回复,和上面一样是以逗号分隔的列表,可以返回所有支持的头部。
- Access-Control-Allow-Credentials(可选) – 和简单请求当中作用相同
- Access-Control-Max-Age(可选) – 以秒为单位的缓存时间。预请求的的发送并非免费午餐,允许时应当尽可能缓存。
- 复杂请求时,浏览器会以OPTIONS的方式发起一个预请求,请求头部包含
- 简单请求下
get和post的区别
- GET请求只能进行url编码,而POST支持多种编码方式
- GET请求在URL中传送的参数是有长度限制的(不同浏览器限制不同),而POST么有(只要看服务器是否限制)。
- 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- GET参数通过URL传递,POST放在Request body中。
302、303、307
- 在HTTP1.0中,302表示客户端发出POST请求后接受到服务器302状态码,必须跟用户确认是否该重发,因为第二次POST时,环境可能已经发生变化(嗯,POST方法不是幂等的),POST操作会不符合用户预期。但是,很多浏览器(user agent我描述为浏览器以方便介绍)在这种情况下都会把POST请求变为GET请求。
- 为了解决这个,HTTP1.1中新增303和307状态码。303表示POST重定向为GET;307表示当发起POST请求要重定向时,要询问用户是否应该在新URI上发起POST方法
- 参考链接
缓存
-
服务端缓存控制
- 响应头存在Cache-Control且非no-cache 和 no-store
- 响应头不存在Cache-Control,但存在Expires
-
客户端缓存控制
- 第一次请求时的响应头必须包含Last-modified和ETag才会在以后的请求携带“if-Modified-Since”、“If-None-Match”、“If-Unmodified-Since”、“If-Match”和“If-Range”(其中前两种是常用的),用于校验资源是否有更新,没有变化则返回“304 Not Modified”。
- 如果响应报文里提供了“Last-modified”,但没有“Cache-Control”或“Expires”,浏览器会使用“启发”(Heuristic)算法计算一个缓存时间,在 RFC 里的建议是:(Date - Last-modified) * 10%。
- ETag 还有强弱之分,强 ETag 要求资源在字节级别必须完全相符,弱 ETag 在值前面有个 “W/” 标记,只有求资源在语义上没有变化,但内部可能会有部分发生改变(例如 HTML 里的标签顺序调整,或者多了几个空格)。
3次握手4次挥手
- 3次握手
- 第一步客户端发起连接请求,发送初始序列号,客户端进入SYN_SENT状态;
- 第二步服务端收到连接请求,确认客户端的SYN,然后返回自己的初始序列号,服务端进入SYN_RECV状态;
- 第三步客户端收到服务端的确认报文后,也确认服务端的SYN,发送后客户端进入连接状态,服务端会在接收到客户端的确认报文后进入连接状态。
-
4次挥手
- 第一步客户端发送释放报文(u是前面已经传送过来的数据的最后一个字节的序号加1),客户端进入FIN-WAIT-1(终止等待1)状态;
- 第二步服务端收到释放报文后,会通知上层应用,并且发送确认报文(v表示服务端当前序列号),然后进入半关闭状态但是继续发送数据,客户端在收到报文后进入FIN-WAIT-2(终止等待2)状态;
- 第三步服务端在数据发送完毕后向客户端发送释放报文(w表示由于后面又发送了数据),并进入LAST-ACK(最后确认)状态;
- 第四步客户端在接收到释放报文后返回确认报文,服务端会在收到报文后关闭,但客户端为了防止该确认报文丢失,将进入TIME-WAIT(时间等待)状态并等待2MSL(最长报文段寿命).