来聊聊面试中的几个不大不小的坑

代码逐风
• 阅读 3822

自从换了公司后这几年经常在忙着招人,面试的时候时不时地挖点坑看看别人会不会往里面跳...
很久没写文章了,就顺便总结一些经验吧...
我不确定能不能写完,写多少是多少吧.
当然文章仅代表个人观点,觉得不对怼我就好.

1.GET 和 POST 请求有什么区别

常规问题了,有些文章说 POST 比 GET 安全啥的,说实话确实是无稽之谈, GET有长度上限啥也是浏览器本身给限制的,

还有一个说法是GET 不能传 body,
于是我就用 express 跑了个小服务

const express = require('express')
const app = express()
app.use(require('express-body'))

/* 测试入口 */
app.use('/test', (req, res) => {
  res.send('test page here')
})

/* 接口 */
app.use('*', (req, res) => {
  res.send(req.body)
})

app.listen('3000', () => {
  console.log('express start')
})

然后我在chrome里用 fetch 试了下

var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");

var raw = JSON.stringify({"hello":"world"});

var requestOptions = {
  method: 'GET',
  headers: myHeaders,
  body: raw,
  redirect: 'follow'
};

fetch("localhost:3000", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));

果不其然,
来聊聊面试中的几个不大不小的坑
浏览器给我抛了个异常说 GET 或者 HEAD 的请求不能有body.

然后我用 xhr 试了下

var data = JSON.stringify({"hello":"world"});

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function() {
  if(this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "http://localhost:3000/");
xhr.setRequestHeader("Content-Type", "application/json");

xhr.send(data);

没想到请求发出去了,但结果返回的是一个空的json
来聊聊面试中的几个不大不小的坑
看了下请求内容,确实没有任何body的影子
来聊聊面试中的几个不大不小的坑
貌似在 chrome 上确实验证了这个说法,但,真的是这么一回事吗?

然后我用postman给服务发了个带body的GET请求
来聊聊面试中的几个不大不小的坑

结果请求成功地返回了我传过去的body信息
来聊聊面试中的几个不大不小的坑

于是我又用 curl 试了下

curl --location --request GET 'localhost:3000' \
--header 'Content-Type: application/json' \
--data-raw '{
    "hello":"world"
}'

来聊聊面试中的几个不大不小的坑
也成功了

那这又是怎么一回事?
难不成跟同源策略一样又是浏览器搞的方言?
于是我去搜了下,大概找到了如下资料 whenToUseGet
看到了如下说明, 我英语不大好大家自行翻译吧

By convention, when GET method is used, all information required to identify the resource is encoded in the URI. There is no convention in HTTP/1.1 for a safe interaction (e.g., retrieval) where the client supplies data to the server in an HTTP entity body rather than in the query part of a URI. This means that for safe operations, URIs may be long. The case of large parameters to a safe operation is not directly addressed by HTTP as it is presently deployed. A QUERY or "safe POST" or "GET with BODY" method has been discussed (e.g., at the December 1996 IETF meeting) but no consensus has emerged.

然后StackOverflow有这么一个问题 HTTP GET with request body大家可以看下里面的回答
协议中有这么一句话

A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.
The response to a GET request is cacheable; a cache MAY use it to
satisfy subsequent GET and HEAD requests unless otherwise indicated
by the Cache-Control header field ([Section 5.2 of [RFC7234]](https://tools.ietf.org/html/r...

也就是说, 浏览器这么做其实也是遵守了HTTP的规范,只是其他的客户端也可以不搭理这个规范,就是传也行不传也行,当然协议是推荐你不传的....如果传了的话就不能保证幂等了,不能幂等就意味着缓存就无意义了.

2.HTTP 缓存

各类中文资料常说的协商缓存强缓存啥的我就不多说了,这俩名词的出处已经无法考证了,可能就是为了方便大家理解缓存特性吧,协议内是没有这个说法的,给一个复杂特征定一个容易记的名词是一种常见的做法,不过传来传去传多了大家都以为真有这么一回事了
然后来看下 no-cacheno-store
这个是 no-cache 的说明

The "no-cache" response directive indicates that the response MUST
NOT be used to satisfy a subsequent request without successful
validation on the origin server. This allows an origin server to
prevent a cache from using it to satisfy a request without contacting
it, even by caches that have been configured to send stale responses.

就是必须通过服务器验证来确定当前资源能否使用
no-store 的说明

The "no-store" response directive indicates that a cache MUST NOT
store any part of either the immediate request or response. This
directive applies to both private and shared caches. "MUST NOT
store" in this context means that the cache MUST NOT intentionally
store the information in non-volatile storage, and MUST make a
best-effort attempt to remove the information from volatile storage
as promptly as possible after forwarding it.

大致就是说不想走缓存就走这个
所以一个误区就是,不想缓存你应该在 Cache-Control 内走 no-store

3.在 <Meta /> 标签内挂 no-cache 能不能阻止缓存页面?

大家应该经常在各类文章里看到,如何让当前网页不缓存,最简单粗暴的方法就是在header里加上

<meta http-equiv="cache-control" content="no-store" />
<meta http-equiv="Pragma" content="no-store" />
<meta http-equiv="expires" content="0" />

于是我按照上述说明在本地挂了个页面
来聊聊面试中的几个不大不小的坑
在第二次访问的时候
直接快乐地304回来了,完全没效果嘛.仔细想下也是嘛,http协议走不走缓存是通过请求头来判定的,还没到body那层就给你判定了要不要走缓存了,再说了,服务器还要知道你发的是html文本,然后解析里面是不是有这么一个meta标签,里面还得有对应的字段啥的,如果是jsp的动态页面你觉得这层拦截操作是在apache里做呢还是在nginx上做?
所以可以证明这个东西无效咯?
作为一名严谨的程序员,我肯定不能这么快下这个结论的嘛,网上虽然各种文章你抄我我抄你,但很多东西并非空穴来风.
于是我去w3翻了一大圈资料,给我找到了一些东西: meta
来聊聊面试中的几个不大不小的坑
HTML3.2里就有了,然后我继续往后翻
众所周知的,w3c在19年放弃发布html和dom的标准,whatwg一家独大了
于是我转头在在whatwg里继续翻

来聊聊面试中的几个不大不小的坑
根本没有嘛.

然后我跑去翻了下

来聊聊面试中的几个不大不小的坑
好家伙,唯一和缓存相关的东西根本不能实现嘛.
所以我们大抵是有一些结论了.这东西不靠谱,挂上去也没效果,该http干的事还是http干.

4.localStorage 和 sessionStorage

大家一般聊到 localStoragesessionStorage 都会说到这个体积的问题,一般是说最多只能用 5MB,
但实际情况真的是这样的吗?

因为比较懒,所以我去找了个小网站测试了下storage
来聊聊面试中的几个不大不小的坑
在chrome下确实是5兆左右,
然后我换了个苹果自带的浏览器 safari
来聊聊面试中的几个不大不小的坑
结果localStorage只有5兆,sessionStorage超过10兆
浏览器的差异一下子就出来了,这和前面说的5兆没啥关系了呀,但这5兆的说法肯定不是空穴来风,于是我又跑去w3看了下协议说明
W3: WebStorage

User agents should limit the total amount of space allowed for storage areas, because hostile authors could otherwise use this feature to exhaust the user's available disk space.
User agents should guard against sites storing data under their origin's other affiliated sites, e.g. storing up to the limit in a1.example.com, a2.example.com, a3.example.com, etc, circumventing the main example.com storage limit.
User agents may prompt the user when quotas are reached, allowing the user to grant a site more space. This enables sites to store many user-created documents on the user's computer, for instance.
User agents should allow users to see how much space each domain is using.
A mostly arbitrary limit of five megabytes per origin is suggested. Implementation feedback is welcome and will be used to update this suggestion in the future.
For predictability, quotas should be based on the uncompressed size of data stored.

上面大致写了如下的意思,为了避免某些别有用心的开发人员耗尽你电脑上的磁盘空间,所以对本地存储的资源体积进行了限制,但是依旧可以被通过改变域名的方式继续存更多的数据,建议是每个源5兆左右.
又是建议... 也就是说,搞大搞小也就是客户端自己看着办,只要你觉得合理,你搞5个G也没问题.

Set 和 Map

一般常见的 Set 能干啥大家应该都会说用来给数组去重,但如果这个数组是[{name: 1}, {name: 2}, {name: 3}, {name: 1}]这种情况呢,这时候我们就会给面试者挖出两个坑.
Map的鸭式辨型解题

const data = [{name:1}, {name:2}, {name:3}, {name:1}]
const maps = new Map()
data.forEach((item) => {
    maps.set(item.name, item)
})
const result = [...maps].map((item) =>item[1])

表面上确实是解决了字面量相关的问题
但是一旦这个对象里面有额外的值的情况,那前面说的方式必然出问题

而第二个坑是 Set 本身就是个指针问题

const a = {name: 1}
const b = {name: 2}
const c = Array.from(new Set([a, a, b, a]))

我们执行这个操作以后只会出现 [{name:1}, {name:2}]的结果,
所以并非对象导致的,而是对象的指针导致的.
所以如果我们能解决指针的问题,或许就能解决这个问题,

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
4年前
VBox 启动虚拟机失败
在Vbox(5.0.8版本)启动Ubuntu的虚拟机时,遇到错误信息:NtCreateFile(\\Device\\VBoxDrvStub)failed:0xc000000034STATUS\_OBJECT\_NAME\_NOT\_FOUND(0retries) (rc101)Makesurethekern
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
4年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
4年前
MBR笔记
<bochs:100000000000e\WGUI\Simclientsize(0,0)!stretchedsize(640,480)!<bochs:2b0x7c00<bochs:3c00000003740i\BIOS\$Revision:1.166$$Date:2006/08/1117
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
代码逐风
代码逐风
Lv1
南朝四百八十寺,多少楼台烟雨中。
文章
3
粉丝
0
获赞
0