zl程序教程

您现在的位置是:首页 >  IT要闻

当前栏目

面试官:GET能上传图片吗?

2023-03-20 14:52:59 时间

这个问题是我以前带过的实习生在面试的时候遇到的一道面试题,当我听到这个问题的时候我觉得挺有意思,下面我来解答一下这个问题吧。 我们都知道图片有两种传输方式base64和file对象。base64的本质是字符串,GET 请求的参数在URL中,因此直接把图的base64数据放到URL里是可以实现GET请求上传图片的。下面的代码就是将file对象转base64后上传的代码:

//img参数类型为图片文件或blob
const getBase64 = img => {
  return new Promise((resolve,reject) => {
    const reader = new FileReader();
    reader.onload = e => {
      resolve(e.target.result);
    };
    reader.onerror = e => reject(e);
    reader.readAsDataURL(img);
  })
}

这就是答案吗?如果是这么认为的话,那我只能说你在面试官那里大概率是不通过的,这是为什么呢?因为GET请求的URL长度是有限的,不同浏览器对长度的限制是不一样的,最长也就大概是 10k左右。但是根据base64的编码原理,图片base64的大小比原文件大了1/3左右,因此base64只能传一些非常小的小图,大图base64会被截断。

TIP:GET长度限制是浏览器设定的,不是GET请求本身设定的,理论上GET请求长度是无限长的,是可以传任意大小的图片。

下面来看这个场景:

<form action="http://127.0.0.1:2022/" method="get">
    <input type="file" name="img">
    <input type="submit">
form>

运行代码,选择图片并提交表单,虽然能提交成功,但接口收不到任何 文件。请求URL变成了http://127.0.0.1:8080/?img=xxx.jpg,而且未携带图片数据。正常来说file对象数据是放在POST请求的body里,并且使用form-data编码。那么我们可以想像GET请求是否有body呢?答案是有的。GET和POST没有本质上的区别,只是HTTP协议的两种请求方式,只是报文规范不同。一个普通的GET请求,收到请求是这样的:

GET /test/?sex=man&name=zhangsan HTTP/1.1
Host: http://localhost:8080
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: Keep-Alive

POST请求是这样:

POST /add HTTP/1.1
Host: http://localhost:8080
Content-Type: application/x-www-form-urlencoded
Content-Length: 40
Connection: Keep-Alive

sex=man&name=Professional 

底层解析报文时并不关心是什么请求,因此GET请求也有body,可以传form-data数据。GET请求能不能带body是HTTP协议来定义的。协议是共同遵守的规则,它带来规范和高效。在HTTP 1.1的RFC文档里并没有禁止GET请求携带body,但也没有定义GET请求 body的语义。 这道面试题主要是考察二进制图片转换成base64、特定场景的URL长度的限制以及HTTP知识。