丰南建设网站,机械代工,热门电影推荐,佛山网站哪家最专业作者简介#xff1a;大家好#xff0c;我是smart哥#xff0c;前中兴通讯、美团架构师#xff0c;现某互联网公司CTO 联系qq#xff1a;184480602#xff0c;加我进群#xff0c;大家一起学习#xff0c;一起进步#xff0c;一起对抗互联网寒冬 作为后端#xff0c;写…
作者简介大家好我是smart哥前中兴通讯、美团架构师现某互联网公司CTO 联系qq184480602加我进群大家一起学习一起进步一起对抗互联网寒冬 作为后端写完接口一定要自测而Postman可以说是最常用的接口测试工具了。但是在介绍Postman的使用之前我们需要复习一下GET/POST请求的一些细节。据我观察其实无论前端还是后端很多人对POST的了解都不够 主要内容
环境准备HTTP请求格式3种POST请求 普通表单提交文件表单提交JSON提交
Postman测试 环境准备
pom
dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency
/dependencies 启动类(ServletComponentScan扫描Servlet)
ServletComponentScan
SpringBootApplication
public class RequestDemoApplication {public static void main(String[] args) {SpringApplication.run(RequestDemoApplication.class, args);}} Servlet
WebServlet(urlPatterns /upload)
Slf4j
public class UploadServlet extends HttpServlet {Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String nameParam request.getParameter(name);String ageParam request.getParameter(age);log.info(GET请求 name:{}, age:{}, nameParam, ageParam);}Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String nameParam request.getParameter(name);String ageParam request.getParameter(age);log.info(POST请求 name:{}, age:{}, nameParam, ageParam);}
} 创建表单页面form.html !DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
body/body
/html HTTP请求格式
HTTP请求的格式可以笼统地分为
请求行请求头空行请求体 启动程序分别发送GET/POST请求并观察HTTP报文当前案例中浏览器使用firefox效果好一些。 GET http://localhost:8080/upload?name周星驰age18 结合上面几张图分析可以得出3个信息
GET请求没有请求体但参数会附在URL后面传递GET请求的参数会经过UrlEncoder编码所以URL的中文是%E5%91...Servlet可以通过request.getParameter()取到参数 POST
!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
bodyh3普通表单提交默认enctypeapplication/x-www-form-urlencoded/h3
form action/upload methodpost用户名:input typetext namename/br年龄:input typetext nameage/brinput typesubmit value提交/
/form/body
/html 结合上面几张图分析也可以得出3个信息
POST请求有请求体参数在请求体里请求体里的参数会经过UrlEncoder编码Servlet通过request.getParameter()可以取到参数 小结
无论GET请求还是POST普通表单提交后端都可以用request.getParameter()取到参数。 不是说GET参数是跟在URL里而POST参数在请求体里吗为什么都可以通过request.getParameter()得到 其实不论是GET还是POST普通表单请求参数都是编码后以namexxxagexxxfilexxx的形式存在的只不过GET的参数跟在URL中而POST放在请求体里。服务器接收到请求后会根据请求类型是GET还是POST分别从对应位置取出namexxxagexxxfilexxx并进行解析、分割然后存在request的一个map中。 这里之所以强调POST表单请求是因为POST其实有很多种形式仅仅是POST表单请求和GET比较相似其他几种POST形式和GET区别较大后面会介绍。 对了有一个很有意思的现象GET和POST普通表单真的太像了对于Spring的Controller来说GET请求的参数可以是散装的也可以用POJO接收POST表单请求也是如此动手试一下 3种POST请求
复习完HTTP请求的格式后我们着重聊聊POST请求GET太简单了略过。
POST请求中开发常见的有3种方式
普通表单提交文件表单提交JSON提交 普通表单提交
上面已经试过了它的特点是
默认的编码方式是enctypeapplication/x-www-form-urlencoded会对每一个表单项进行编码周星驰 -- %E5%91%A8%...不能提交文件流后端可以通过request.getParameter()得到每个参数 有两点需要证明一下默认编码是什么、能否提交文件流。 我们在HTML的表单中并没有指定enctype然后HTTP报文中却显示 所以POST表单请求默认编码方式是enctypeapplication/x-www-form-urlencoded。我们从name“周星驰”这个参数的乱码也可以看出肯定经过了某种编码。 如果你观察过Postman的POST其实就有这一个选项 那么enctypeapplication/x-www-form-urlencoded这种编码格式能不能上传文件流呢比如一个用户表单能不能同时上传头像呢
!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
bodyh3普通表单提交默认enctypeapplication/x-www-form-urlencoded/h3
form action/upload methodpost用户名:input typetext namename/br年龄:input typetext nameage/br选择文件input typefile namefile/brinput typesubmit value提交/
/form/body
/html
WebServlet(urlPatterns /upload)
Slf4j
public class UploadServlet extends HttpServlet {Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String nameParam request.getParameter(name);String ageParam request.getParameter(age);log.info(GET请求 name:{}, age:{}, nameParam, ageParam);}Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String nameParam request.getParameter(name);String ageParam request.getParameter(age);// 根据参数名获取文件String fileParam request.getParameter(file);log.info(POST请求 name:{}, age:{}, file:{}, nameParam, ageParam, fileParam);}
} 通过实验我们发现POST普通表单是无法上传文件的最多只能传递文件名请求体中是filexxxx.png。 文件表单提交
所谓文件表单提交指的是此时表单中含有文件项。
在上面普通表单提交的实验中我们已经发现光是设置input输入框为typefile是不够的这样只是提交文件名而不是文件流。 归根到底造成这种现象的原因在于当前表单的编码格式不对。POST请求默认的编码格式是enctypeapplication/x-www-form-urlencoded也就是对各个表单项的参数值进行URL编码后以namexxxagexxxfilexxx的形式放入请求体。 最终file仅仅提交了文件名而不是文件流。 那么怎样才能把整个文件提交上去呢
只要把POST请求的编码改为enctypemultipart/form-data即可。 form-data形式提交
!DOCTYPE html
html langen
headmeta charsetUTF-8titleTitle/title
/head
bodyh3文件表单提交必须指定enctypemultipart/form-data/h3
form action/upload methodpost enctypemultipart/form-data用户名:input typetext namename/br年龄:input typetext nameage/br选择文件input typefile namefile/brinput typesubmit value提交/
/form/body
/html 看起来好像稳了请求体有点不一样了
但是回到SpringBoot一看坏了 之前普通表单提交虽然无法上传文件流但好歹传了文件名呢而这次干脆啥都没提交上去。 但是真的什么都没提交上去吗 其实前端已经提交成功只是后端没按正确方式接收。 失败原因分析
我们观察一下设置enctypemultipart/form-data后请求体的变化 application/x-www-form-urlencoded编码的请求体参数 multipart/form-data编码的请求体参数 浏览器会在发起POST请求时自动带上Content-Type请求头
普通表单的Content-Type是application/x-www-form-urlencoded图一文件表单的Content-Type是multipart/form-data图二 Content-Type的作用是告诉服务器本次提交的参数编码类型而它的值取决于enctype。 为什么multipart/form-data能实现文件上传这要从multipart/form-data独特的格式说起。 multipart/form-data的意思是多部件传输请求即把表单的每一项都作为一个部件单独发送每一个部件其实都包含
请求头空行 请求体 -----------------------------5708493371455355810326359340
Content-Disposition: form-data; namename卿驰
-----------------------------5708493371455355810326359340
Content-Disposition: form-data; nameage18
-----------------------------5708493371455355810326359340
Content-Disposition: form-data; namefile; filenameavatar.png
Content-Type: image/pngPNG
简单来说就是这样 其中file项显示乱码恰恰代表本次上传的是文件你本地直接用文本编辑器打开一张照片也是如此。 所以此时所有POST参数包括整个文件都已经发送到后端了。 在application/x-www-form-urlencoded格式下服务器会帮我们分割参数并存入Map中所以我们才能通过request.getParameter()获取参数。但由于这次ContentType是multipart/form-data服务器将不再对参数进行解析而是直接放入了request的inputStream中如果想要获取参数开发人员必须自己处理。 SpringMVC接收File
要想得到请求参数大致的处理流程是
识别分隔符-----------5708493371455355810326359340根据分隔符把参数切成三份从请求头中得到参数名从请求体中得到参数值。如果Content-Type:image/png还要把字符转为图片 是不是觉得很烦 所幸已经有人替我们做了。如果你用的是Servlet那么可以引入Apache的commons-fileupload依赖 它的原理就是上面说的那样。 如果你用的是SpringMVC那就更方便了人家已经集成了commons-fileupload依赖在请求到达Controller方法之前已经替我们把文件封装到MultipartFile组件中 Slf4j
RestController
public class UploadController {PostMapping(/springUpload)public void upload(String name, Integer age, MultipartFile file) {log.info(name:{}, age:{}, fileName:{}, name, age, file.getOriginalFilename());}
}此时参数file是整个文件我们可以通过file.getInputStream()获取文件流。 整个过程大致是这样的
POST表单请求 -- namexxxagexxx服务器能处理存入Map -- request.getParameter()
POST文件上传 -- 服务器无法处理全部塞入Request的InputStream -- 第三方组件分割多个参数File参数会被单独包装成MultipartFile(包含文件流、文件名等) 上面是通过HTM的form表单实现的enctype指定form-data我们也可以使用Postman发送表单请求 JSON提交
引入JQuery啥的比较麻烦我们直接用Postman模拟。总之HTMLAjax能做的都可以通过Postman模拟。 Postman测试
GET请求 POST请求none
none就是没有请求体但编码还是默认的enctypeapplication/x-www-form-urlencoded POST请求x-www-form-urlencoded
有请求体编码是默认的enctypeapplication/x-www-form-urlencoded POST请求multipart/form-data POST请求rawJson
虽然上面说了那么多种POST请求形式但实际上前后端分离后已经很少使用其他几种POST形式了基本都是JSON。 它们的使用频率大概是
none几乎为0%
x-www-form-urlencoded10%
multipart/form-data20%比如OSS文件上传有可能会配合MultipartFile单独写一个
rawjson70%绝大多数POST都是JSON后端需要用RequestBody接收 所以这里我们不再演示文件提交而是演示JSON请求以POST新增User为例 POJO
Data
public class UploadUser {/*** 姓名*/private String name;/*** 年龄*/private Integer age;/*** 地址*/private String address;} Controller
RestController
Slf4j
public class UserController {/*** 新增用户* param user* return*/PostMapping(addUser)public UploadUser addUser(UploadUser user) {log.info(user:{}, user);return user;}} Postman发起POST请求(rawJSON) 后端接口压根没取到参数 因为现在发起的请求是JSON所以后面必须明确以JSON格式解析 请求成功 什么时候加RequestBody
POST请求是JSON时必须加RequestBodyPOST请求时普通表单时不用加加了反而错POST请求是文件上传时不用加用MultipartFile 规则这么多说了等于没说。关键还是要明白RequestBody到底意味着什么
RequestBody的意思是SpringMVC将会用jackson解析请求体中参数其他非JSON格式的参数会直接抛异常 SpringBoot默认使用jackson解析JSON 打开Postman的请求控制台 分别发送x-www-form-urlencoded、form-data、rawJSON三种请求 当前端指定Content-Type为json也就是发送JSON请求时后端就要加RequestBody其他GET/POST普通表单/POST文件表单都不需要加了反而错。 示意图 三种POST形式参数其实都是在请求体中但格式有点不同。 如果把GET请求的格式也加上你会发现 可怜的服务器其实只会处理x-www-form-urlencoded这种简单的格式做一些参数切割工作然后封装到Map中方便Servlet通过request.getParameter()获取。
其他的无论multipart/form-data还是application/json都需要第三方框架在后面补充完成。 最后我相信部分同学可能对RequestBody/ResponseBody如何起作用比较感兴趣如果后面有多余篇幅的话可以一起探究一下。其实不是特别重要。 提问
1.GET和POST的请求参数分别在哪默认是什么编码
2.文章把POST请求分为哪几种请求参数存放的位置一样吗
3.普通表单请求和文件表单请求的区别是
4.文件表单提交后Servlet的request.getPatameter()方法就废了。如果不借助file-upload你怎么获取参数
5.后端接口方法什么时候加RequestBody
6.怎么用Postman分别发送文件表单、普通表单、JSON请求
请在评论区尝试作答 作者简介大家好我是smart哥前中兴通讯、美团架构师现某互联网公司CTO 进群大家一起学习一起进步一起对抗互联网寒冬