Skip to content
返回

HTTP 网络请求

目录

点击展开

HTTP 网络请求

HTTP 和 Ajax 是前后端沟通的桥梁,面试重点考察,无论工作经验长短。

TCP 是如何建立连接的,三次握手,四次挥手

参考答案

::: details

三次握手

四次挥手

三次握手四次挥手,客户端都是主动方,服务端都是被动方。在状态方面:三次握手的客户端和服务端都是由原来的 closed 变为 established,四次挥手的客户端和服务端都是由原来的 established 变为 closed。

:::

参考资料

::: details

HTTP 几个版本的区别

参考答案

::: details

HTTP/0.9 - 单行协议

HTTP/1.0 - 多类型支持

HTTP/1.1 - 持久连接

HTTP/2.0 - 多路复用

HTTP/3.0 - QUIC 协议

:::

参考资料

::: details

HTTP 常见的状态码

参考答案

::: details

:::

HTTP 常见 Header

参考答案

::: details

请求头

响应头

:::

URL 包含哪些部分?

参考答案

::: details

URL (Uniform Resource Locator) 包含以下部分:

  1. 协议 (protocol):如 http://https://ftp://

  2. 域名 (domain):如 www.example.com

    • 子域名:www
    • 主域名:example
    • 顶级域名:com
  3. 端口号 (port):如 :80:443(可选,HTTP 默认 80,HTTPS 默认 443)

  4. 路径 (path):如 /blog/article

  5. 查询参数 (query string):如 ?id=123&name=test

  6. 锚点/片段标识符 (fragment):如 #header

示例:https://www.example.com:80/blog/article?id=123&name=test#header

:::

GET 和 POST 请求的区别

参考答案

::: details

:::

Ajax Fetch Axios 三者有什么区别?

参考答案

::: details

Ajax、Fetch 和 Axios 都是用于发送 HTTP 请求的技术,但有以下区别:

Ajax (Asynchronous JavaScript and XML)

Fetch

Axios

使用建议:

:::

Fetch 和 XMLHTTPRequest 有什么区别?

参考答案

::: details

语法和使用

功能特性

错误处理

浏览器支持

:::

什么是 Restful API ?

参考答案

::: details

RESTful API 是一种软件架构风格,用于设计网络应用程序的接口。主要特点:

资源导向

HTTP 方法对应操作

无状态

统一接口

:::

什么是 GraphQL ?

参考答案

::: details

GraphQL 是一种用于 API 的查询语言和运行时,由 Facebook 开发。主要特点:

查询灵活性

类型系统

单个端点

主要操作类型

优点

缺点

:::

参考答案

::: details

Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据。

主要特点:

常用属性:

使用场景:

限制:

:::

参考答案

::: details

主要原因是保护用户隐私和安全:

隐私问题

安全风险

技术影响

:::

如何理解 Session ?

参考答案

::: details

Session 是服务器端的会话管理机制:

基本概念

工作流程

  1. 用户首次访问服务器时,服务器创建 Session 并生成 SessionID
  2. 服务器将 SessionID 通过 Cookie 发送给客户端
  3. 客户端后续请求会自动携带包含 SessionID 的 Cookie
  4. 服务器通过 SessionID 找到对应 Session 并识别用户

特点

使用场景

与 Cookie 的区别

:::

什么是 JWT 描述它的工作过程

参考答案

::: details

JWT (JSON Web Token) 是一种开放标准,用于在各方之间安全地传输信息。

组成部分(用 . 分隔的三部分):

工作流程:

  1. 用户登录成功后,服务器创建 JWT

    • 设置 Header 和 Payload
    • 使用密钥生成签名
    • 将三部分组合成 token
  2. 服务器将 token 返回给客户端

    • 客户端存储在 localStorage 或 cookie 中
  3. 后续请求携带 token

    • 通常放在 Authorization header
    • 格式:Bearer <token>
  4. 服务器验证 token

    • 检查签名是否有效
    • 验证是否过期
    • 验证其他声明(claims)

特点:

安全考虑:

:::

参考资料

::: details

:::

JWT 如何自动更新 token ?

参考答案

::: details

JWT token 自动更新主要有以下几种方案:

双 token 机制

工作流程:

  1. 用户登录后获取 access token 和 refresh token
  2. 使用 access token 访问接口
  3. access token 过期时,使用 refresh token 获取新的 access token
  4. refresh token 过期时,需要重新登录
// 前端示例代码
async function request(url, options) {
  try {
    const res = await fetch(url, {
      ...options,
      headers: {
        Authorization: `Bearer ${getAccessToken()}`,
      },
    })

    if (res.status === 401) {
      // access token 过期,尝试刷新
      const newToken = await refreshToken()
      if (newToken) {
        // 使用新 token 重试请求
        return request(url, options)
      } else {
        // refresh token 也过期,跳转登录
        redirectToLogin()
      }
    }

    return res
  } catch (error) {
    console.error(error)
  }
}

滑动过期机制

无感刷新机制

最佳实践:

:::

什么是 SSO 单点登录,描述它的工作过程

参考答案

::: details

SSO (Single Sign On) 单点登录是一种身份验证机制,允许用户使用一组凭证访问多个相关但独立的系统。

基本概念

工作流程:

用户首次访问系统

SSO 认证中心处理

回到系统 A

访问系统 B

实现方式:

优点:

缺点:

:::

参考资料

::: details

:::

什么是跨域?如何实现跨域通讯?

参考答案

::: details

跨域是指浏览器的同源策略限制,当前域名的 JavaScript 代码试图访问其他域名下的资源时会受到限制。

同源的定义:

跨域解决方案:

CORS(跨域资源共享)

JSONP

代理服务器

postMessage

WebSocket

document.domain(已废弃)

最佳实践:

:::

参考资料

::: details

:::

HTTP 请求跨域时为何要发送 options 请求

参考答案

::: details

OPTIONS 请求是 CORS 预检请求(Preflight Request),用于检查实际请求是否可以安全地发送。

触发条件:

工作流程:

  1. 浏览器发送 OPTIONS 预检请求,包含:

    • Origin:请求来源
    • Access-Control-Request-Method:实际请求使用的方法
    • Access-Control-Request-Headers:实际请求使用的请求头
  2. 服务器响应预检请求,返回:

    • Access-Control-Allow-Origin:允许的源
    • Access-Control-Allow-Methods:允许的方法
    • Access-Control-Allow-Headers:允许的请求头
    • Access-Control-Max-Age:预检请求的缓存时间
  3. 如果预检通过,浏览器才会发送实际请求

优化建议:

:::

参考资料

::: details

:::

参考答案

::: details

OPTIONS 请求通常不会携带 Cookie。它是一个预检请求,用于检查实际请求是否可以安全地发送。浏览器在发送 OPTIONS 请求时,不会自动附带 Cookie 和 Authorization 等认证信息,除非明确设置了 credentials 选项。

如果需要在 OPTIONS 请求中携带 Cookie,可以在请求中设置 credentials: 'include',但通常不推荐这样做,因为 OPTIONS 请求的目的就是检查跨域请求的安全性,而不是进行身份验证。

:::

简述浏览器的缓存策略

参考答案

::: details

浏览器缓存策略主要分为两种:强缓存和协商缓存。

强缓存

协商缓存

缓存位置(优先级从高到低):

  1. Service Worker
  2. Memory Cache(内存缓存)
  3. Disk Cache(硬盘缓存)
  4. Push Cache(HTTP/2)

最佳实践:

:::

参考资料

::: details

:::

什么是图片防盗链,如何实现?

参考答案

::: details

图片防盗链是指服务器通过 HTTP 协议中的 Referer 字段来判断请求是否来自合法站点,从而防止其他网站直接引用本站图片资源。

实现方式:

服务器端实现

Nginx 配置示例:

location ~ .*\.(gif|jpg|jpeg|png|bmp)$ {
    valid_referers none blocked server_names *.example.com;
    if ($invalid_referer) {
        return 403;
        # 或者返回替代图片
        # rewrite ^/ /path/to/default.jpg break;
    }
}

其他防盗链方案:

注意事项:

:::

简述 HTTPS 加密过程

参考答案

::: details

HTTPS 使用 TLS/SSL 协议进行加密,主要包含以下步骤:

客户端发起请求

服务器回应

客户端验证证书

生成会话密钥

开始加密通信

特点:

:::

移动端 H5 如何抓包?

参考答案

::: details

移动端 H5 抓包主要有以下几种方法:

Charles/Fiddler

优点:

vConsole

<script src="https://unpkg.com/vconsole/dist/vconsole.min.js"></script>
<script>
  var vConsole = new VConsole();
</script>

Chrome Remote Debug

Safari Web Inspector

注意事项:

:::

script 标签的 defer 和 async 有什么区别

参考答案

::: details

script 标签的 defer 和 async 属性都是用于控制脚本的加载和执行时机:

普通 script

defer

async

使用建议:

示例:

<!-- 普通脚本 -->
<script src="script.js"></script>

<!-- defer 脚本 -->
<script defer src="script.js"></script>

<!-- async 脚本 -->
<script async src="script.js"></script>

:::

prefetch 和 dns-prefetch 分别是什么

参考答案

::: details

prefetch 和 dns-prefetch 是两种不同的资源预加载技术:

prefetch

<!-- 预加载资源 -->
<link rel="prefetch" href="/next-page.js" />
<link rel="prefetch" href="/images/large.jpg" />

dns-prefetch

<!-- DNS 预解析 -->
<link rel="dns-prefetch" href="//example.com" />
<link rel="dns-prefetch" href="//api.example.com" />

使用建议:

相关技术:

:::

WebSocket 和 HTTP 协议有什么区别

参考答案

::: details

WebSocket 和 HTTP 的主要区别:

连接特性

通信方式

数据格式

应用场景

性能

支持性

:::

如何上传文件?使用 fetch 或者 axios

参考答案

::: details

文件上传主要有以下几种方式:

使用 FormData

// HTML
<input type="file" id="file">

// fetch
const file = document.querySelector('#file').files[0]
const formData = new FormData()
formData.append('file', file)

fetch('/upload', {
    method: 'POST',
    body: formData
})

// axios
const formData = new FormData()
formData.append('file', file)

axios.post('/upload', formData, {
    headers: {
        'Content-Type': 'multipart/form-data'
    }
})

使用 Base64

// 将文件转为 Base64
function fileToBase64(file) {
  return new Promise((resolve) => {
    const reader = new FileReader()
    reader.onload = () => resolve(reader.result)
    reader.readAsDataURL(file)
  })
}

// fetch
const base64 = await fileToBase64(file)
fetch('/upload', {
  method: 'POST',
  body: JSON.stringify({ file: base64 }),
  headers: {
    'Content-Type': 'application/json',
  },
})

// axios
const base64 = await fileToBase64(file)
axios.post('/upload', {
  file: base64,
})

多文件上传

// HTML
<input type="file" multiple id="files">

// fetch
const files = document.querySelector('#files').files
const formData = new FormData()
Array.from(files).forEach(file => {
    formData.append('files', file)
})

fetch('/upload', {
    method: 'POST',
    body: formData
})

// axios
const formData = new FormData()
Array.from(files).forEach(file => {
    formData.append('files', file)
})

axios.post('/upload', formData)

注意事项:

:::

如何上传大文件?

参考答案

::: details

大文件上传主要有以下几种方案:

切片上传

实现步骤: 前端切片

function createFileChunk(file, size = 1 * 1024 * 1024) {
  const chunks = []
  let cur = 0
  while (cur < file.size) {
    chunks.push(file.slice(cur, cur + size))
    cur += size
  }
  return chunks
}

上传切片

async function uploadChunks(chunks) {
  const requests = chunks.map((chunk, index) => {
    const formData = new FormData()
    formData.append('chunk', chunk)
    formData.append('index', index)
    return axios.post('/upload', formData)
  })
  await Promise.all(requests)
}

发送合并请求

await axios.post('/merge', {
  filename: file.name,
  size: chunks.length,
})

断点续传

秒传

性能优化

:::

参考资料

::: details

:::

如何实现图片懒加载?

参考答案

::: details

IntersectionObserver API

const io = new IntersectionObserver((entries) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      entry.target.src = entry.target.dataset.original
      entry.target.removeAttribute('data-original')
      io.unobserve(entry.target)
    }
  })
})
const imgs = document.querySelectorAll('img[data-original]')
imgs.forEach((item) => {
  io.observe(item)
})

原生 loading 属性

let viewHeight = window.innerHeight
function lazyLoad() {
  let imgs = document.querySelectorAll('img[data-original]')
  imgs.forEach((el) => {
    let rect = el.getBoundingClientRect()
    if (rect.top < viewHeight) {
      let image = new Image()
      image.src = el.dataset.original
      image.onload = function () {
        el.src = image.src
      }
      el.removeAttribute('data-original')
    }
  })
}
lazyLoad() // 页面初始加载时调用一次
document.addEventListener('scroll', lazyLoad)

:::

参考资料

::: details

:::

在网络层面可做哪些性能优化?

参考答案

::: details

网络性能优化可以从以下几个方面考虑:

减少请求数量

减小资源体积

CDN 优化

HTTP 优化

资源加载优化

接口优化

监控和分析

:::

参考资料

::: details

:::


Share this post on:

上一篇文章
Vue 使用
下一篇文章
TS 面试题