目录
Cookie,sessionStorage和localStorage的区别
JS的数据类型有哪些
- 基本数据类型
- null / undefined / number / string / boolean / symbol
- 引用数据类型
- object:包括对象,数组和函数
判断数据类型的几种方法
- typeof:检测到数组,对象,null,函数都会返回object,所以不是很准确
- 变量 instanceof 类型:因为此方法的原理是判断其在原型链上能否找到该类型的原型,所以只能判断引用数据类型,不能用来判断基本数据类型
- Object.prototype.toString.call():比较准确,常用
讲一下对this指向的理解
- 简言之,this指向总是指向函数的直接调用者
- 全局函数:this指向window
- 对象内部的函数:this指向对象本身
- 构造函数:this指向生成的实例
- 箭头函数:箭头函数本身没有this,所以会捕获上下文中的this
- 匿名函数:this指向window
call() / apply() / bind的区别
- 首先,三者都是用来改变this指针的指向的,并且第一个参数都是新指向的变量
- call()和apply()直接返回指针新指向的变量,会立即执行,而bind()返回的是一个函数,需要调用才会执行
- 第二个参数,call()和bind()是直接写入的,而apply是以数组的形式写入的
构造函数和普通函数的区别
- 构造函数函数名的首字母一般会大写,普通函数小写
- 调用函数时,构造函数要使用new 函数名()的方法,普通函数直接函数名()
箭头函数和普通函数的区别
- 普通函数可以是具名函数也可以是匿名函数(匿名函数的this指向window),箭头函数都是匿名函数
- 箭头函数不能用于构造函数
- 原理:虽然箭头函数在原型链上,但他没有prototype属性,而constructer是写在prototype中的
- 箭头函数本身没有this, 也不能改变this的指向,其this指向上下文;普通函数有自己的this且可以通过call(), apply(), bind()改变this指向,其this指向调用他的对象
- 箭头函数不能绑定arguments,需要使用rest代替
什么是闭包
- 函数A里面包含了函数B,而函数B 中又使用了函数A 中的变量,那么函数B被称为闭包。
- 闭包的应用场景
- 模拟私有变量
// 外部无法直接使用count变量,不过可以通过increment和decrement来操作count // 保护了数据也不影响数据使用,在模块化开发中很有用 function createCounter() { let count = 0; return { increment: function() { count++; return count; }, decrement: function() { count--; return count; } }; } const counter = createCounter(); console.log(counter.increment()); // 1 console.log(counter.decrement()); // 0
高阶函数或回调函数(防抖节流)
高阶函数 -- 一个函数的返回值是另一个函数
回调函数 -- 将一个函数作为另一个函数的参数进行传递
闭包的缺陷
每次创建闭包时,都会在内存中保留一份变量的的引用,当闭包引用了不再需要的变量时,内存将无法释放,过多使用闭包会导致内存泄漏
简单讲一下防抖和节流
- 防抖和节流都是为了防止短时间内频繁操作导致性能效率不高的问题,所以防抖和截留的本质是对定时器的使用
- 防抖:触发定时器后取消上一次触发再重新倒计时
- 常用场景:搜索输入、密码校验、窗口大小调整
function myDebounce(fn, delay) { let timer = null return () => { if(timer) clearTimeout(timer) // 1. 清理上一个定时器 timer = setTimeout(() => { // 2. 加一个新定时器 fn() // 3. 定时器到点执行操作 timer = null // 4. 执行结束恢复timer空闲标志哦 }, delay) } } const inputDOM = document.querySelector("input") function handleInput(){ console.log('发请求', this); } inputDOM.oninput = myDebounce(handleInput,1000) /* 注意clearTimeout(timer)和timer = null的区别 clearTimeout会清除定时器,清除后timer是一个普通变量 timer = null是将timer直接赋为一个null变量,和定时器没关系,定时器依然存在,只是没有被timer指向而已 */
- 节流:触发定时器后在其规定时间内不能二次触发
- 常用场景:重复提交表单、滚动加载
function myThrottle(fn, delay) { let startTime = 0 return () => { let now = Date.now() // 第一次必触发 // 第二次开始,和第一次触发的间隔需要大于等待的时间才允许 if(now - startTime >= delay) { fn() startTime = now } } } const inputDOM = document.querySelector("input") function handleInput(){ console.log(`发请求`, this); } inputDOM.oninput = myThrottle(handleInput,1000)
var / let / const
- var作用域为该语句所在的函数内且存在变量提升
- let作用域为该语句所在的代码块内,没有变量提升
- 在相同的作用域下,let不能被重复声明,var可以
- const声明常量无法修改,引用类型数据可以修改
- 因为const的作用原理是限制指针指向的内容不可改变。常量的值就保存在指针指向的位置,而对于引用类型数据,指针指向的只是保存实际数据的一个指针,他只能保证这个指针不变,不能保证指针指向的数据不变。
- Object.freeze()可以实现对象完全不可修改
- let / const会出现暂存死区
var arr = [2,5,7,3,6,1,9] function no(){ console.log(arr); var arr = [1,2] } no()
如以上代码中,由于函数内部查询到有arr,所以不会再向外查找,但是let又没有变量提升,所以会出现暂存死区,导致程序报错
JS常见函数
- 数组相关函数
- push() / pop():从尾部添加/删除一个元素
- unshift() / shift():从头部添加 / 删除一个元素
- slice():根据开始和结束的索引号提起数组元素
- splice():增加/删除/替换数组元素
- indexOf():根据元素查询其索引号
- reverse():数组元素翻转
- forEach():进行数组遍历
- map() / filter():前一个对原数组所有的元素进行加工计算,后一个对原数组中的元素按照某一条件进行筛选
- some() / every():前一个当数组元素有任意一个满足条件则返回true,后一个当数组元素全部满足条件才返回true
- reduce((pre, curr, index, arr) => {})
- sort((a, b) => b - a)
- 字符串相关函数
- indexOf() / charAt():查询,前一个根据字符查询位置,后一个根据位置查询字符
- substr() / substring():字符串提取,前一个是根据开始位置和截取长度来截取,后一个是根据开始位置和结束位置来截取
- concat():字符串拼接
- split():使用分隔符将字符串分割为数组
- replace():替换一个字符
- trim():删除字符串头部和尾部的空白符,空白符包括换行符,空格与制表符
怎么实现数组去重
- 搞一个新的数组,使用for循环结合indexOf判断
- 使用ES6中的Set()方法
- 使用双重for循环
forEach / for in 和for of的区别
- forEach一般用来遍历数组,for in用来遍历对象
- for of既可以遍历数组,也可以遍历对象
- 遍历对象时,for in遍历出来的是键名,for of遍历出来的是键值
forEach / map / filter的区别
- forEach没有return值,map和filter有return值
- map处理数据,filter筛选数据
- 都是不会改变简单引用数据类型,但是对象数组这种形式会有影响
怎么判断对象中是否存在某个属性
- 使用in
- 使用方法hasOwnProperty()
- 使用obj[a]直接判断
ES6中Set()和Map()的区别
- Set()要求元素不能重复,且以类似于数组的形式保存
- Map()可以重复,以类似于对象的形式保存
谈谈深拷贝和浅拷贝
- 简而言之,浅拷贝拷贝到的只是一个存放数据的地址,更改拷贝后的数据会导致原数据也发生变化,而深拷贝拷贝到的是具体的数据或属性
- 实现浅拷贝
- 使用扩展符...
let arr = [1, 2, 3, 4] let newArr = [...arr] let obj = { a: 1, b: { c: 1 } } let newObj = {...obj} console.log(newArr, newObj)
- slice()
let arr = [1, 2, 3, 4] let newArr = arr.slice(0, arr.length) console.log(newArr);
- Object.assign()
let arr = [1, 2, 3, 4] let newArr = Object.assign([], arr) let obj = { a: 1, b: { c: 1 } } let newObj = Object.assign({}, obj) console.log(newArr, newObj)
- concat()
let arr = [1, 2, 3, 4] let newArr = arr.concat() console.log(newArr)
- 实现深拷贝
- JSON.stringify + JSON.parse
- 使用插件lodash的cloneDeep函数
- 递归函数
function deepClone(obj) { let resClone = Array.isArray(obj) ? [] : {} for(let key in obj) { if(typeof obj[key] == 'object') { resClone[key] = deepClone(obj[key]) } else { resClone[key] = obj[key] } } return resClone }
mouseover和moouseenter有什么区别
- mouseenter和mouseleave相对应,这两个事件都不会冒泡
- mouseover和mouseout相对应,会触发事件冒泡
简述AJAX
- ajax可以实现在页面不刷新的情况下向服务端发送请求
- 原生ajax实现步骤
- 创建一个XMLHttpRequest对象
- 使用open()方法来与服务器建立连接
- 使用send()方法来向服务器发送请求
- 如果是post请求,可以在send括号内写入参数,同时需要设置请求头
- 监听服务器的响应,根据状态信息和状态码来进行下一步操作
//get方式发送请求 function ajax(url){ //1. 创建XMLHttpRequest对象 var xhr = new XMLHttpRequest(); //2. 连接服务器 //参数:请求的方式,文件的路径,是否异步 xhr.open('GET',url,true) //3. 发送请求 xhr.send() //4. 监听状态的改变,当readystate发生改变时调用 xhr.onreadystatechange = function(){ //存储XMLHttpRequest的状态信息 if(xhr.readystate == 4){ //响应的状态码 if(xhr.status == 200){ //获得字符串形式的响应数据 var data = xhr.responseTEXT //获得xml形式的响应数据 var data = xhr.responseXML return data } } } } //post方式发送请求 //3.设置请求头信息 ajax.setRequestHeader('content-type','application/x-www-form-urlencoded'); //4.发送请求 ajax.send('name='+uname+"&contents="+contents);
- 常见的状态信息
- 0:请求未初始化
- 1:服务器已建立连接
- 2:请求已接收
- 3:正在处理请求
- 4:请求已完成
- 常见的状态码
- 2XX:请求成功
- 200:服务器响应正常
- 201:请求成功并在服务器创建了新的资源
- 202:服务器已接受请求,但并未处理
- 3XX:重定向问题
- 301:永久重定向
- 304:资源在首次请求后没有任何修改(容易在get方式下发生)
- 4XX:请求错误,客户端问题
- 400:未找到请求的资源
- 401:无法理解请求的格式
- 403:没有权限
- 404:资源不存在
- 405:不允许使用该方法访问资源
- 407:需要代理服务器身份验证
- 414:请求的URL太长
- 415:content-Type格式不正确,服务器无法处理
- 5XX:服务器问题
- 500:服务器内部错误
- 503:服务器崩了/服务器没了
- ajax的缺点
- 对搜索引擎的支持性很差
- 与服务器交互的环节暴露在外,安全性较差
JS实现异步的方法有哪些
- 回调函数:将需要异步执行的函数作为回调函数,可能会造成回调地狱
- 事件监听:当事件发生时触发函数
- promise
简述promise
- 为了防止异步代码嵌套调用回调函数产生回调地狱的问题,ES6提出使用promise来解决异步编程,promise是一个对象,可以将异步操作以同步的方式来表示
- promise的两个参数
- resolve:请求成功时调用
- reject:请求失败时调用
- promise的回调函数
- then:当检测到转换为fulfilled状态就执行该回调
- catch:当检测到转换为rejected状态就执行该回调
- promise的三种状态
- pending:默认状态
- fulfilled:成功状态,一旦调用resolve函数立刻到这个状态
- rejected:失败状态,一旦调用reject函数立刻到这个状态
- 状态一旦发生改变不可逆转
- promise的all
- 接受一个数组,可以同时封装多个promise,当每个异步事件均为成功状态才执行下一步
- promise的race
- 接受一个数组,可以同时封装多个promise,哪个先返回状态就以哪个promise的状态来决定下一步
- promise的缺点
- 一旦执行无法中途取消
- 处于pending状态时无法知道发展到了什么阶段
Cookie,sessionStorage和localStorage的区别
- Cookie可存放4k左右,sessionStorage可以存放5M左右,localStorage可以存放5-10M
- Cookie会与服务器端进行通信,每次通信都会被放在请求头中,其他两个不参与服务器通信
- Cookie和sessionStorage在关闭标签页就会被清除(刷新不会被清除),localStorage需要手动清除
- Cookie可以通过后台代码手动设置过期时间
get/post的区别
- get传参可以在url中看见,而且长度有限制,post看不见,也没有限制
- get在页面刷新和回退时没有影响,post会重新提交
- get可以被缓存,post不会被缓存
- get会保留在历史记录中,post不会
- get更适合向服务器请求数据,post更适合向服务器发送数据
移动端:什么是点击延迟,什么是点击穿透
- 由于移动端在除了有点击操作外,还有双击的操作,用户在进行了依次点击后,浏览器不确定是要执行点击还是等待双击,所以会先等300ms,造成300ms的延迟
- 而由于点击延迟,但页面中有两个元素是上下层关系的时候,我们想要关闭上层元素,在上层被隐藏后,点击函数才执行到快要结束,这时候发现上层元素没了,所以会触发下层的点击事件,造成点击穿透
JS中运算符的运算规则
- 算数运算符
- +:
- 与非数字型计算时,会进行拼接
- 与数字型计算时,会进行加法
- - / * / /:
- 与字符型计算时,会有隐式转换
- 运算符的优先级
- 小括号>一元运算符>算数运算符>比较运算符>逻辑运算符(先与后或)>赋值运算符
继承与原型
- 概念:
- 与其他语言一样,js也是有继承的,只是叫法不同,其他语言中子继承父,js中即子的原型是父。当我们创建一个对象时,对象会有一个_proto_的属性,该属性就代表该对象的父级
- 当我们访问一个对象的属性或方法时,会顺着原型链一步一步地向上查找,直到找到这个属性(方法)或者查到头了(null代表到头了)才停止
- 函数:
- 函数也是一个对象,但同时还有一种函数叫做构造函数,构造函数有自己的实例对象
- 因此函数有两个代表原型的参数(prototype和_proto_),prototype是构造函数的原型,_proto_是构造函数所对应的实例对象的原型
- 当构造函数自己被当作对象调用时,他的原型就是prototype,当使用构造函数的实例对象进行调用时,他的原型就是_proto_
- 构造函数.prototype === 实例对象._proto_
function User() { console.warn('一个函数') } // 首先,函数也是一个对象,那他一定也有原型 let a = new User() //将User当作构造函数来使用,a是User()的实例对象 console.dir(User) console.dir(a) // 打印结果可以看出: //user有一个prototype和一个[[Prototype]](与_proto_一个意思),而a只有[[Prototype]], 而且User.prototype === a._proto_
- 常用的原型方法
- instanceof --- 判断变量的类型
- 原理:通过查找原型链上是否有对象的原型来进行判断
- 因为对象才有原型链,所以此方法不能用来检测基本数据类型
let a = 1 //此方法a就是基本数据类型Number let b = new Number(1) // 此方法b是通过构造函数创建的,所以b instanceof Number为true let arr = [] // 字面量创建数组等同于new Array(),所以arr instanceof Array为true
- isPrototypeOf --- 检测一个对象是否在另一个对象的原型链上
let arr = [] let obj = {} console.log(Object.prototype.isPrototypeOf(obj)) // true;Object.prototype在obj的原型链上 console.log(b.isPrototypeOf(obj)) // false;arr与obj之间没有关系 Object.setPrototypeOf(arr, obj) // 将obj设置为arr的原型 console.log(obj.isPrototypeOf(arr)) //true
- call和apply --- 改变this指针,借用原型方法
- 第一个参数都是this,第二个参数apply只能传一个,call可以传多个
let a = { a: 1, b: 2, c: 3 } let b = { d: 4, e: 5, f: 6 } a.__proto__.sum = function(a, b, c) { return a + b + c } // 给a的原型上加一个方法 //通过call或者apply改写原型的指向,让b也能使用a原型上的方法 a.sum(a.a, a.b, a.c) a.sum.apply(b, Object.values(b)) // apply第二个只接受一个参数,不能展开传 a.sum.call(b, ...Object.values(b)) // call可接受多个参数,需要展开传参
- 判断对象中是否含有某个属性
- a in obj
- obj.hasOwnProperty(a)
- 区别:in同时会检测该对象的原型链上是否有相关属性,hasOwnProperty只检测自己有没有,不检测原型链
跨域及其解决方案
- 概念:跨域的本质是因为浏览器的同源策略,同源策略是指浏览器出于用户安全考虑,只允许本域(同协议,同IP,同端口的网址)下的接口交互与资源访问。
- 同源策略的限制
- Cookie,sessionStorage,LocalStorage等本地内容
- Dom节点操作
- Ajax接口请求
- 解决跨域的方法
- jsonp
- 原理:利用html中的link,href,src以及script中的src是不受跨域影响的
- 使用方法:与后端协商好请求数据与响应数据都是用jsonp格式
- CORS跨资源共享
- 使用方法:让后端在响应头中配置‘Access-Contorl-Allow-Origin’, 设置为协议,IP,端口与本域一致
- document.domain
- proxy代理
- 原理:在本地创建一个虚拟服务器,发送请求数据,同时接受请求的数据,利用服务器与服务器间的交互
- 使用方法:
// vue.config.js中设置 devServer: { proxy:{ "/api": { target: "http://www.baidu.com", // 当我们发送请求时的URL中有/api时,会将在/api前面的路径替换成target的值。 changeOrigin: true, //开启代理:在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样服务端和服务端进行数据的交互就不会有跨域问题 pathRewrite: { //重写匹配的字段,如果不想出现在请求路径上,可以重写为"" "^/api": "/api" } }, }, }
new的原理及实现
- 创建一个空对象
- 将新对象的原型指向构造函数的原型
- 使用call或者apply改变构造函数的this指向,并将参数也传递给空对象,同时获取返回值
- 判断返回值是否为对象,是则返回返回值,不是则返回空对象
function Func(Fn, args) { let obj = {} // 创建空对象 obj.__proto__ = Fn.prototype // 连接原型 let res = Fn.call(obj, ...args) // 改变this,传递参数 return res instanceof Object ? res : obj // 返回值为对象使用返回值,不是对象使用obj } let Con = function(name, age) { this.name = name this.age = age } var newObj = Func(Con, [1, 2])
浏览器的运行机制
- 进程与线程
- 一个程序实例的运行需要创建进程来完成,而进程又采用多个线程来运行
- 浏览器有哪些进程
- 主进程 -- 负责页面展示,用户交互,数据存储;
- 网络进程 -- 负责数据请求;
- 渲染进程 -- 每个站点都有自己的渲染进程,负责将三件套转换为树结构;
- GUI渲染线程 -- 负责解析HTML, CSS文件,构建DOM树和CSS树;
- JS引擎线程 -- 负责处理js脚本程序,常听的如V8引擎;
- 事件触发线程 -- 辅助JS引擎线程,负责存放异步请求,当异步请求到达执行时间后会被添加到JS引擎队列中;
- GPU进程 -- 负责3D绘制,将树结构数据绘制为页面;
- 插件进程 -- 如果有用到插件,会单独开这个进程。
- 从输入URL到页面展示经历了什么
- 创建进程
- 创建主进程,判断用户输入,将输入的URL交给网络进程;
- 网络进程查找本地缓存,判断是否命中强缓存,如命中则将缓存交还主进程;
- 进行数据请求
- 如未命中,通过DNS对域名进行解析,生成IP地址;
- 通过IP地址来建立TCP连接,发送HTTP请求,接收服务器响应信息;
- 如响应信息命中协商缓存,则将缓存交还主进程;
- 如未命中,判断状态码,如3开头,则重定向,如200成功,则读取数据交还主进程;
- 关闭TCP连接;
- 进行页面渲染
- 根据响应信息的content-Type来判断响应体的类型;
- 如果为html类型,GUI线程解析html代码并构建相应的DOM树;
- 解析CSS并构建相应的规则树;
- CSS树和DOM树一起生成一个render树;
- 将render树信息发送给GPU进程,GPU会绘制页面来显示;
- 解析JS代码会重新生成DOM树和CSS树,引发页面重新渲染;
- 在解析HTML或CSS代码时如遇到JS代码,GUI线程会被挂起,优先执行JS引擎线程
浏览器缓存机制
- 一次请求的过程
- 浏览器发送请求 ->浏览器缓存判断是否存在缓存(判断强缓存)
- 不存在 -> 直接发送请求到服务器
- 存在 -> 判断缓存是否失效
- 未失效 -> 将缓存中的信息返给浏览器
- 失效了 -> 将缓存标识(开始协商缓存)返给浏览器,浏览器携带缓存标识发送请求到服务器
- 返回304 - 资源无更新,浏览器从缓存获取信息
- 返回200 - 资源已更新,将新资源存入缓存
- 强缓存标识字段
- Expires: 响应头中,值为服务器返回的该请求结果的缓存到期时间
- Cache-Control:响应头中
- private:所有内容都会被缓存(默认值,只有客户端能缓存)
- public: 所有内容都会被缓存(客户端和代理服务器都能缓存)
- no-cache:协商缓存
- no-store: 不会缓存
- max-age:缓存失效倒计时
- Cache-Control优先级高于Expires
- 协商缓存标识字段
- Last-Modified:响应头中,值为改资源在服务器端最后被修改的时间
- If-Modified-Since: 请求头中,值为上次服务器端返回的Last-Modified
- Etag:响应头中,值为服务器返回的关于该资源的唯一标识
- If-None-Match: 请求头中,值为上次服务器端返回的Etag
- 缓存存放位置
- 内存缓存(memory cache)
- 磁盘缓存(disk cache)
- 区别
- 内存缓存读取快,但时效短,关闭浏览器清空缓存
- 磁盘缓存读取较慢,但存储量大且时效性长,关闭浏览器不会立即清空
垃圾回收机制
- 概念:不再用到的内存没有被及时清理,导致内存占用越来越高,这就叫内存泄漏,为了避免内存泄漏,js有自己的垃圾收集器,进行垃圾回收
- 垃圾回收方式:
- 标记清除:当变量进入环境时将其标记,离开时再将其标记,垃圾收集器开始工作后销毁带离开标记的值并释放相应内存
- 引用计数:跟踪每个值被引用的次数,垃圾回收器会释放引用次数为0的值所占用的内存
回流与重绘
- 回流 -- 当元素的尺寸,结构,位置或属性发生改变导致重新渲染
- 页面首次渲染
- 窗口或元素大小发生变化
- 触发事件或者方法
- 重绘 -- 元素的改变并不影响他的位置,只根据新样式来重新渲染
- 元素颜色,透明度发生变化
- 避免回流
- 减少table布局
- 避免频繁操作样式和DOM
- display:none时不会引发回流和重绘,可以利用
- 使用绝对定位来脱离文档流
简述纯函数
- 概念
- 返回值不依赖于外部的变量,执行该函数也不会对外部的变量产生影响,有确定的输入与输出,并且不依赖于外部的变量或者函数,这样的函数称之为纯函数
- 纯函数举例 -- slice() 截取数组但不会对原数组产生影响
defineProperty
- Object.defineProperty(obj, prop, desc)
- obj -- 需要定义属性的当前对象
- prop -- 当前需要定义的属性名
- desc -- 属性描述符
- writable -- 是否只读
- enumerable -- 是否美剧
- configurable -- 是否可配置
http和https的区别
- http是明文传输,https是SSL加密传输的
- http端口一般为80,https端口为443
- https需要花钱申请证书
- https在数据传输之前需要进行身份认证,且数据经过加密,所以更安全,但这种客户端与服务器的相互身份认证也导致通信时间加长,响应比http慢一些
数组与对象的相互转换
- 数组转对象
- 展开运算符...
- Object.assign()
- 循环遍历
- 键值对可以使用Object.fromEntries()
let arr = [1, 2, 3] let obj1 = {...arr} // {0: 1, 1: 2, 2: 3} let obj2 = Object.assign({}, arr) // {0: 1, 1: 2, 2: 3} let obj3 = {} arr.forEach((item, index) => { obj3[index] = item }) // {0: 1, 1: 2, 2: 3} let arr1 = [['a', 1], ['b', 2]] let obj4 = Object.fromEntries(arr) // {a: 1, b: 2}
- 对象转数组
- Object.values()
- Object.keys()
- 键值对 -- Object.entries()
let obj = {a: 1, b: 2} let arr1 = Object.entries(obj) // [['a', 1], ['b', 1]] let arr2 = Object.values(obj) // [1, 2] let arr3 = Object.keys(obj).map(item => obj[item]) // [1, 2] let arr4 = Object.keys(obj).map(item => [item, obj[item]]) // [['a', 1], ['b', 1]]
交换变量
- 使用中间变量
- 使用数组
- 解构赋值
let a = 1; let b = 2 // 中间变量 let temp temp = a a = b b = temp // 数组 let arr = [a, b] a = arr[1] b = arr[2] // 解构赋值 [a, b] = [b, a]
http请求报文
- 请求行 -- 包含请求方法 URL http协议版本
- 请求头
- Accept -- 告诉服务器客户端要接收什么类型的相应
application/json 接收json格式的数据 text/plain 接收纯文本格式的数据 text/html 接收HTML文档格式的数据 */* 接收任意类型
- Accept-Encoding -- 告诉服务器可接受的编码类型
gzip deflate compress br identity 不支持任何压缩方式
Accept-Language -- 告诉服务器可处理的自然语言
en-US 美国英语 zh-CN 简体中文 zh-TW 繁体中文 zh-HK 香港中文 fr-FR 法语 de-DE 德语
Connection -- 告诉服务器是否需要保持连接
keep-alive 保持连接 close 关闭连接
Host -- 指定目标服务器的主机名和端口号
Referer -- 告诉服务器从那个页面链接过来的
User-Agent -- 告诉服务器所使用的操作系统和浏览器相关信息
Content-Type -- 告诉服务器请求体数据类型
application/json json格式 text/plain 纯文本数据 application/xml xml格式 text/xml xml格式 multipart/form-data 文件流 application/x-www-form-urlencoded 表单数据
- 空行 --通知服务器请求头结束
- 请求数据
GET 请求资源 POST 修改资源 PUT 传输文件 DELETE 删除文件 HEAD 仅获取响应报文首部 CONNECT 用隧道协议进行通信 OPTIONS 查询资源支持的请求方法 TRACE 查询已发送的请求是怎么样被修改的 ALLOW 所支持的各种方法
一些距离变量