关于html:来聊聊面试中的几个不大不小的坑

37次阅读

共计 5661 个字符,预计需要花费 15 分钟才能阅读完成。

自从换了公司后这几年常常在忙着招人, 面试的时候时不时地挖点坑看看他人会不会往里面跳 …
很久没写文章了, 就顺便总结一些教训吧 …
我不确定能不能写完, 写多少是多少吧.

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 协定走不走缓存是通过申请头来断定的, 还没到
所以能够证实这个货色有效咯?
作为一名谨严的程序员, 我必定不能这么快下这个论断的嘛, 网上尽管各种文章你抄我我抄你, 但很多货色并非空穴来风.
于是我去 w3 翻了一大圈材料, 给我找到了一些货色: meta

HTML3.2 里就有了, 而后我持续往后翻
家喻户晓的,w3c 在 19 年放弃公布 html 和 dom 的规范,whatwg 一家独大了
于是我转头在在 whatwg 里持续翻

  • WHATWG-The Meta Element


基本没有嘛.

而后我跑去翻了下

  • WHATWG-Meta Extensions


好家伙, 惟一和缓存相干的货色基本不能实现嘛.
所以咱们大抵是有一些论断了. 这货色不靠谱, 挂上去也没成果, 该 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}]的后果,
所以并非对象导致的, 而是对象的指针导致的.
所以如果咱们能解决指针的问题, 或者就能解决这个问题,

正文完
 0