Skip to content

网络基础类

1. 跨域

很多种⽅法,但万变不离其宗,都是为了搞定同源策略 。重用的有 jsonpiframecorsimgHTML5 postMessage 等等 。其中用到 html 标签进行跨域的原理就是 html 不受同源策略影响 。但只是接受 Get 的请求⽅式, 这个得清楚。

延伸 1: img iframe script 来发送跨域请求有什么优缺点?

  1. iframe
  • 优点:跨域完毕之后 DOM 操作和互相之间的 JavaScript 调用都是没有问题的
  • 缺点:1.若结果要以 URL 参数传递, 这就意味着在结果数据量很大的时候需要分割传递,巨烦 。2.还有⼀个是 iframe 本身带来的, 母页面和 iframe 本身的交互本身就有安全性限制。
  1. script
  • 优点:可以直接返回 json 格式的数据, 方便处理
  • 缺点:只接受 GET 请求方式
  1. 图片 ping
  • 优点:可以访问任何 url ,⼀ 般用来进行点击追踪,做页面分析常用的方法
  • 缺点:不能访问响应文本, 只能监听是否响应

延伸 2:配合 webpack 进行反向代理?

webpackdevServer 选项里面提供了⼀个 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 协议无状态中的 状态 到底指的是什么?!

  • 【状态】 的含义就是:客户端和服务器在某次会话中产生的数据
  • 那么对应的 【无状态】 就意味着:这些数据不会被保留
  • 通过增加 cookiesession 机制,现在的网络请求其实是有状态的
  • 在没有状态的 http 协议下, 服务器也⼀定会保留你每次网络请求对数据的修改,但这跟保留每次访问的数据是不⼀样的,保留的只是会话产生的结果, 而没有保留会话

3. http-cache:就是 http 缓存

  1. 首先得明确 http 缓存的好处
  • 减少了冗余的数据传输,减少网费
  • 减少服务器端的压⼒
  • Web 缓存能够减少延迟与网络阻塞, 进而减少显示某个资源所用的时间
  • 加快客户端加载网页的速度
  1. 常见 http 缓存的类型
  • 私有缓存 (⼀般为本地浏览器缓存)
  • 代理缓存
  1. 然后谈谈本地缓存

本地缓存是指浏览器请求资源时命中了浏览器本地的缓存资源, 浏览器并不会发送真正的请求给服务器了 。它的执⾏过程是

  • 第⼀次浏览器发送请求给服务器时,此时浏览器还没有本地缓存副本, 服务器返回资源给浏览器, 响应码是 200 OK , 浏览器收到资源后, 把资源和对应的响应头⼀起缓存下来
  • 第⼆次浏览器准备发送请求给服务器时候, 浏览器会先检查上⼀次服务端返回的响应头信息中的 Cache-Control , 它的值是⼀个相对值, 单位为秒,表示资源在客户端缓存的最大有效期, 过期时间为第⼀次请求的时间减去 Cache-Control 的值, 过期时间跟当前的请求时间比较, 如果本地缓存资源没过期,那么命中缓存,不再请求服务器
  • 如果没有命中, 浏览器就会把请求发送给服务器, 进⼊缓存协商阶段。

与本地缓存相关的头有: Cache-ControlExpiresCache-Control 有多个可选值代表不同的意义, 而 Expires 就是⼀个日期格式的绝对值。

Cache-Control

Cache-ControlHTPP 缓存策略中最重要的头, 它是 HTTP/1.1 中出现的, 它由如下⼏个值

  • no-cache :不使用本地缓存 。需要使用缓存协商, 先与服务器确认返回的响应是否被更改, 如果之前的响应中存在 ETag ,那么请求的时候会与服务端验证, 如果资源未被更改,则可以避免重新下载
  • no-store :直接禁止游览器缓存数据,每次用户请求该资源,都会向服务器发送⼀个请求,每次都会下载完整的资源
  • public :可以被所有的用户缓存, 包括终端用户和 CDN 等中间代理服务器 。
  • private :只能被终端用户的浏览器缓存,不允许 CDN 等中继缓存服务器对其缓存。
  • max-age :从当前请求开始, 允许获取的响应被重用的最长时间 (秒) 。

例如: Cache-Control: public, max-age=1000 表示资源可以被所有用户以及代理服务器缓存, 最长时间为 1000 秒。

Expires

ExpiresHTTP/1.0 出现的头信息, 同样是用于决定本地缓存策略的头,它是⼀个绝对时间, 时间格式是如 Mon, 10 Jun 2015 21:31:12 GMT , 只要发送请求时间是在 Expires 之前,那么本地缓存始终有效, 否则就会去服务器发送请求获取新的资源 。如果同时出现 Cache-Control:max-ageExpires ,那么 max-age 优先级更高 。他们可以这样组合使用

js
Cache-Control: public
Expires: Wed, Jan 10 2018 00:27:04 GMT

所谓的缓存协商

当第⼀次请求时服务器返回的响应头中存在以下情况时

  • 没有 Cache-ControlExpires
  • Cache-ControlExpires 过期了
  • Cache-Control 的属性设置为 no-cache

那么浏览器第⼆次请求时就会与服务器进行协商,询问浏览器中的缓存资源是不是旧版本, 需不需要更新,此时, 服务器就会做出判断, 如果缓存和服务端资源的最新版本是⼀致的,那么就⽆需再次下载该资源, 服务端直接返回 304 Not Modified 状态码, 如果服务器发现浏览器中的缓存已经是旧版本了,那么服务器就会把最新资源的完整内容返回给浏览器,状态码就是 200 Ok ,那么服务端是根据什么来判断浏览器的缓存是不是最新的呢?其实是根据 HTTP 的另外两组头信息,分别是: Last-Modified/If-Modified-SinceETag/If-None-Match

Last-ModifiedIf-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

这组头信息是基于资源的修改时间来判断资源有没有更新, 另⼀种方式就是根据资源的内容来判断,就是接下来要讨论的 ETagIf-None-Match

ETagIf-None-Match

ETag/If-None-MatchLast-Modified/If-Modified-Since 的流程其实是类似的, 唯⼀的区别是它基于资源的内容的摘要信息 ( 比如 MD5 hash ) 来判断

浏览器发送第⼆次请求时,会把第⼀次的响应头信息 ETag 的值放在 If-None-Match 的请求头中发送到服务器,与最新的资源的摘要信息对比, 如果相等, 取浏览器缓存, 否则内容有更新, 最新的资源连同最新的摘要信息返回 。用 ETag 的好处是如果因为某种原因到时资源的修改时间没改变,那么用 ETag 就能区分资源是不是有被更新。

第⼀次请求返回的响应头:

Cache-Control: public, max-age=31536000 ETag: "15f0fff99ed5aae4edffdd6496d7131f"

第⼆次请求的请求头信息:

If-None-Match: "15f0fff99ed5aae4edffdd6496d7131f"

  • session : 是⼀个抽象概念, 开发者为了实现中断和继续等操作,将 user agentserver 之间⼀对⼀的交互,抽象为“会话”, 进而衍生出“会话状态”,也就是 session 的概念
  • cookie :它是⼀个世纪存在的东⻄, http 协议中定义在 header 中的字段, 可以认为是 session 的⼀种后端无状态实现

现在我们常说的 session , 是为了绕开 cookie 的各种限制, 通常借助 cookie 本身和后端存储实现的,⼀ 种更高级的会话状态实现

session 的常⻅实现要借助 cookie 来发送 sessionID

5. 安全问题, 如 XSS 和 CSRF

  • XSS :跨站脚本攻击, 是⼀种网站应用程序的安全漏洞攻击, 是代码注⼊的⼀种 。常⻅方式是将恶意代码注⼊合法代码里隐藏起来, 再诱发恶意代码,从而进⾏各种各样的非法活动

    防范:记住⼀点“所有用户输⼊都是不可信的”,所以得做输⼊过滤和转义

  • CSRF :跨站请求伪造,也称 XSRF , 是⼀种挟制用户在当前已登录的 Web 应用程序上执⾏非本意的操作的攻击方法 。与 XSS 相比, XSS 利用的是用户对指定网站的信任, CSRF 利用的是网站对用户网页浏览器的信任

    防范:用户操作验证 (验证码), 额外验证机制 ( token 使用) 等