总结前后端常用的HTTP接口协议传参方法

首发:公众号《赵侠客

前言

做了多年的后端开发,给前端提供过的接口没有1万个也有1000多个,对接过的前端开发人员没有100人也是50人,联调过的前端开发人员从刚毕业的新人到工作过10多年的老程序员,从江南萌妹到东北壮汉几乎什么样的人都遇到过,在与前端对接过程中一直都会遇到一个问题,就是我们后端接口提供好了,自测也通过了,前端却说接口不通,当我们去排查时发现大都不是接口不通,很多情况是前端使用的姿势不对,比如接口明明写的参数是放到ULR路径上,前端却传到了queryString上,接口明明写的是使用application/x-www-form-urlencoded格式,前端却传了application/json格式,所以本文总结常用的前后端传参数据格式,方便前端与后端开发人员更好的理解HTTP接口协议传参格式。

一、通过HTTP URL传参数

这种方式是最简单,也是最常用的传参方式,通常用于前端从后端获取数据,通过URL传参也分为两种,一种是将参数放在URL路径上,另一种是将参数放在QueryString上,也就是URL?后面

HTTP报文格式

GET /user/1?userName=admin&arrays=a,b,c,d&ids=1&ids=2&ids=3&ids=4

注意事项:

  1. 路径 /user/1 上的1是通过URL路径传参数,这种RestFul风格的传参方式,有些前端会搞错
  2. userName=admin 这种就是简单的QueryString传参,是最常见的,一般不会搞错
  3. arrays=a,b,c,d 这种是通过QueryString传数组,其实就是使用,分隔
  4. ids=1&ids=2&ids=3&ids=4这种也是传数组参数的一种方式,一般用的比较少,容易出错

后端接口代码

我们使用SpringMVC框架编写接口,可以通过@PathVariable@RequestParam两个注解来接收上面参数,主要有三种方法:

  1. 第一种是在方法上一个一个的来接收参数;
  2. 第二种是使用Map<String,Object>接收来参数;
  3. 第三种是封装个UserDTO对象来接收。
java 复制代码
    @GetMapping("/user/{id}")
    public UserDTO request(@PathVariable Long id, String userName, String[] arrays,@RequestParam List<Long> ids) {
        return UserDTO.builder().id(id).build();
    }

    @GetMapping("/user2/{id}")
    public Map<String,Object> user2(@PathVariable Long id,@RequestParam Map<String,Object> map)    {
        return map;
    }

    @GetMapping("/user3/{id}")
    public UserDTO user3(@PathVariable Long id, UserDTO user) {
        return user;
    }
    
    @Data
    public class UserDTO {
        private Long id;
        private String userName;
        private String[] arrays;
        private List<Long> ids;
    }
    

注意事项:

  1. 接收数组参数时可以使用String[]List<Long>两种数据类型;
  2. 使用Map<String,Object> map接收参数时 Value的类型要是Object类型,并且增加@RequestParam
  3. 使用User对象接收参数时不要增加@RequestParam注解

前端调用接口代码

前端对于这种传参数方式直接把所有参数拼接到URL上就好了

js 复制代码
        var request = new XMLHttpRequest();
        request.open('GET', 'http://localhost/user/1?userName=admin&arrays=a,b,c,d&ids=1&ids=2&ids=3&ids=4', true);
        request.responseType = 'json';
        request.onload = function () {
            var data = this.response;
            console.log(data);
        };
        request.send();

注意事项:

  1. 如果传的参数不是URL安全的需要进行URLEncode
  2. POSTPUTDELETE方法也是支持通过URL传参的
  3. 使用这种URL拼接不同浏览器支持的最大参数长度是不一样的,以下是不同浏览器支持参数的最大长度:
浏览器 URL长度限制
IE浏览器 2048字节
360极速浏览器 65536字节
Firefox(Browser) 2118字节
Safari(Browser) 80000字节
Opera(Browser) 190000字节
Google(chrome) 8182字节

二、通过HTTP Body传参数

通过HTTP Body传参数主要用于前端向服务端提交数据,如添加数据修改数据上传文件 等等,通过Body传参常用的数据格式主要有以下3种:

  1. application/x-www-form-urlencoded 也就是表单提交,body报文中使用key=value拼接参数;
  2. application/json 将数据转成JSON格式放在Body中;
  3. multipart/form-data 用于文件上传。

HTTP报文格式

  • application/x-www-form-urlencoded格式报文:
html 复制代码
POST /user3/1
Content-Type: application/x-www-form-urlencoded

userName=admin&arrays=a,b,c,d&ids=1&ids=2&ids=3&ids=4
  • application/json格式报文:
html 复制代码
GET /user4/1
Content-Type: application/json

{
    "id": 1,
    "userName": "admin",
    "arrays": [
        "a",
        "b",
        "c",
        "d"
    ],
    "ids": [
        1,
        2,
        3,
        4
    ]
}

注意事项:

  1. GET方法也可以通过Body传参数,这点很多人会觉得GET方法不能通过Body传参,不过只能传application/json,使用过elasticsearch应该知道,在搜索数据是就是通过GET方法传JSON数据的。

后端接口代码

SpringMvc框架中接收Bodyapplication/x-www-form-urlencoded类型参数和在URLQueryString传参数是通用的,接收application/json需要使用@RequestBody注解。

java 复制代码
    @RequestMapping("/user3/{id}")
    public UserDTO user3(@PathVariable Long id, UserDTO user) {
        return user;
    }

    @RequestMapping("/user4/{id}")
    public UserDTO user4(@PathVariable Long id,@RequestBody UserDTO user) {
        return user;
    }

    @RequestMapping("/user5/{id}")
    public UserDTO user4(@PathVariable Long id,@RequestBody String user) {
        return JSONUtil.toBean(user,UserDTO.class);
    }

注意事项:

  1. @RequestBody 注解可以直接使用DTO来接收,也可以使用String来接收在手动转成DTO,这个方法在不知道要接收的数据有哪些字段时非常有用,可以将对方传的完整数据打印出来。

前端调用接口代码

js 复制代码
function sendFormUrl() {
        var request = new XMLHttpRequest();
        request.open('POST', 'http://localhost/user3/1', true);
        request.responseType = 'json';
        request.onload = function () {
            console.log(this.response);
        };
        var formData = new FormData();
        formData.append('userName', "admin");
        formData.append('arrays', "a,b,c,d");
        formData.append('ids', "1");
        formData.append('ids', "2");
        formData.append('ids', "3");
        formData.append('ids', "4");
        request.send(formData);
    }

    function sendJson() {
        var request = new XMLHttpRequest();
        request.open('POST', 'http://localhost/user4/1', true);
        request.responseType = 'json';
        request.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
        request.onload = function () {
            console.log(this.response);
        };
        var body = {
            "userName": "admin",
            "arrays": [
                "a",
                "b",
                "c",
                "d"
            ],
            "ids": [
                1,
                2,
                3,
                4
            ]
        }
        request.send(JSON.stringify(body));
    }

注意事项:

  1. multipart/form-data主要用于文件上传,可以参数我的另一篇文章: 《一个Demo搞定前后端大文件分片上传、断点续传、秒传》

通过Header传参数

通过Header传参主要用于一些通用的用户认证信息,比如常用的 Authentication: Bearer Cookie

HTTP报文格式

html 复制代码
GET /user7/1
Accept: application/json
userName : admin
Cookie: userName=admin;
arrays: a,b,c,d
ids:1
ids:2
ids:3
ids:4

注意事项

  1. 使用SpringMVC请求报java.lang.IllegalArgumentException: The HTTP header line [username : admin] does not conform to RFC 7230. The request has been rejected.因为userName这些自 定义请求头不符合RFC 7230标准所以被拒绝了,增加配置 reject-illegal-header: off可解决

application.yml中增加:

xml 复制代码
server:
  port: 80
  tomcat:
    reject-illegal-header: off

后端接口代码

获取Header参数可以通过request.getHeader(header)依次获取,也可以通过@CookieValue@RequestHeader来获取

java 复制代码
    @RequestMapping("/user6/{id}")
    public User user6(@PathVariable Long id, HttpServletRequest request) {
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()){
            String header= headerNames.nextElement();
            log.info("{}->{}",header,request.getHeader(header));
        }
        return User.builder().id(id).build();
    }

    @RequestMapping("/user7/{id}")
    public User user7(@PathVariable Long id, @CookieValue String userName, @RequestHeader String[] arrays, @RequestHeader List<Long> ids) {
        return User.builder().id(id).userName(userName).arrays(arrays).ids(ids).build();
    }

前端调用接口代码

js 复制代码
    function sendHeader() {
        var request = new XMLHttpRequest();
        request.open('GET', 'http://localhost/user7/1', true);
        request.responseType = 'json';
        request.setRequestHeader("arrays","a,b,c,d");
        request.setRequestHeader("ids","1");
        request.setRequestHeader("ids","2");
        request.setRequestHeader("ids","3");
        request.setRequestHeader("ids","4");
        request.onload = function () {
            console.log(this.response);
        };
        request.send();
    }

注意事项:

  1. Cookie是浏览器自动添加了,不需要通过request.setRequestHeader("userName","admin")添加

总结

本文总结了前后端通过HTTP接口协议传参的常用方法,并从HTTP协议、后端JAVA代码、前端JS代码演示每种参数的报文格式、后端获取方法和前端调用方法,当然还有一些更高级的传参方式,比如websocketsse等基于HTTP的实时推送协议。

相关推荐
豐儀麟阁贵几秒前
8.5在方法中抛出异常
java·开发语言·前端·算法
q***385117 分钟前
SpringBoot + vue 管理系统
vue.js·spring boot·后端
zengyuhan50330 分钟前
Windows BLE 开发指南(Rust windows-rs)
前端·rust
醉方休34 分钟前
Webpack loader 的执行机制
前端·webpack·rust
前端老宋Running42 分钟前
一次从“卡顿地狱”到“丝般顺滑”的 React 搜索优化实战
前端·react.js·掘金日报
隔壁的大叔42 分钟前
如何自己构建一个Markdown增量渲染器
前端·javascript
用户44455436542644 分钟前
Android的自定义View
前端
WILLF1 小时前
HTML iframe 标签
前端·javascript
用户638982245891 小时前
使用Hutool的ExcelWriter导出复杂模板,支持下拉选项级联筛选
后端
程序员鱼皮1 小时前
10个免费的网站分析工具,竟然比付费的更香?
后端·程序员·数据分析