作者:李旭光
引用请标明出处
前言
就在前天,公司里一位新入职的前端小伙伴找到我说遇到了一个问题,自己写的vue代码本地运行是好用的,但是打包后提给后台就访问不了接口了,刚开始我以为是代理配置的有问题,但是经过检查也没什么问题,因为是个get
方法,所以我就直接在浏览器地址里敲了api地址,也能正常获取到数据,那么这么看就不是代理或者接口的问题,后来我又看了下调试工具,network中根本就没发出请求,我怀疑是直接前台就拦截了,最后我发现他这个api参数超级长,长的相当吓人,可以看一下下图。
我记得url是有长度限制的,于是我就把url变短再次请求,虽然因为参数不全,接口报了错,但是发出去了,由此我定位应该是url超长,因为vue中配置了什么导致的访问被拦截了。于是我就开始了搜索引擎查找解决方案之旅,接下来就把我了解到的信息一一整理。
URL 限制
首先我在网上找到了一份资料介绍了URL长度的相关资料,从下面可以看出,从HTTP协议层面以及Get请求层面都没有什么限制,这个限制来自于浏览器或者服务器的限制。
Microsoft Internet Explorer (Browser)
IE浏览器对URL的最大限制为2083个字符,如果超过这个数字,提交按钮没有任何反应。
Firefox (Browser)
对于Firefox浏览器URL的长度限制为65,536个字符。
Safari (Browser)
URL最大长度限制为 80,000个字符。
Opera (Browser)
URL最大长度限制为190,000个字符。
Google (Browser)
URL最大长度限制为8182个字符。
Apache (Server)
能接受最大url长度为8,192个字符。
Microsoft Internet Information Server(IIS)
能接受最大url的长度为16,384个字符。
而且,中文会进行编码,一个汉字编码后会生成9个字符,这样算来,IE下最多也就能输入231个中文,再多就完蛋了,那么通过get请求传递参数就会显得很麻烦。
通常情况下,这种超长参数的请求我们都会用post,有些地方也会说post请求没有长度限制,但是前面说了,实际上HTTP协议层面并没有任何的限制,限制只出现在浏览器或者服务器限制,get和post请求在底层上其实是一样的。
最后项目修改了请求类型,把 get
请求改成了 post
请求,在网上实际还找到了另外两个方案,如果对同一组参数频繁访问的化,也可以用 post+get
请求的方式去处理,或者用 sessionStorage
下面简单介绍一下。
- 将预览内容
post
到服务端,根据一个唯一标识生成缓存(有效时间5分钟),将唯一标识返回到前端,前端通过get方式传递唯一标识请求预览逻辑,拿到缓存的内容后渲染到页面。需要说明的是这里的缓存必须是分布式的。 - 通过H5的会话缓存
sessionStorage
将预览内容存储在浏览器,打开预览页后从sessionStorage
中拿到内容就可以渲染出页面了。
上述两种方案都不太符合我们的项目所以最终还是选择了最简单的方式
GET VS POST
多数浏览器对于POST采用两阶段发送数据的,先发送请求头,再发送请求体,即使参数再少再短,也会被分成两个步骤来发送(相对于GET),也就是第一步发送header数据,第二步再发送body部分。HTTP是应用层的协议,而在传输层有些情况TCP会出现两次连结的过程,HTTP协议本身不保存状态信息,一次请求一次响应。对于TCP而言,通信次数越多反而靠性越低,能在一次连结中传输完需要的消息是最可靠的,尽量使用GET请求来减少网络耗时。如果通信时间增加,这段时间客户端与服务器端一直保持连接状态,在服务器侧负载可能会增加,可靠性会下降。
GET请求能够被cache,GET请求能够被保存在浏览器的浏览历史里面(密码等重要数据GET提交,别人查看历史记录,就可以直接看到这些私密数据)POST不进行缓存。
GET参数是带在URL后面,传统IE中URL的最大可用长度为2048字符,其他浏览器对URL长度限制实现上有所不同。POST请求无长度限制(目前理论上是这样的)。
GET提交的数据大小,不同浏览器的限制不同,一般在2k-8K之间,POST提交数据比较大,大小靠服务器的设定值限制,而且某些数据只能用 POST 方法「携带」,比如 file。
全部用POST不是十分合理,最好先把请求按功能和场景分下类,对数据请求频繁,数据不敏感且数据量在普通浏览器最小限定的2k范围内,这样的情况使用GET。其他地方使用POST。
GET 的本质是「得」,而 POST 的本质是「给」。而且,GET 是「幂等」的,在这一点上,GET 被认为是「安全的」。但实际上 server 端也可以用作资源更新,但是这种用法违反了约定,容易造成 CSRF(跨站请求伪造)。
写在最后
以上是这次遇到问题后学到的一点知识,可能并不全面,后续如果遇到了类似的问题会继续丰富这篇文章。