前后端数据传参详解

1. Http数据传参的两种方式

  1. uri传参
    数据参数写在uri地址中,可以为查询参数,也可以为路径参数,一般get请求方式用的多。
    优点:一个TCP传输就可以将参数传递给服务器,速度快。
    缺点:参数直接暴露在浏览器中,不安全。
  2. body传参
    数据参数写在body体中,有多种content-type格式:json、xml、form-data,一般post请求方式用的多。
    优点:相对安全,没有大小限制。
    缺点:需要两个TCP传输,第一次传输head,第二次传输body。

注意,上面说的post和get,并不是说post只能用body传参,get只能用uri传参,实际上,想怎么传参是我们码农自己定的,你可以在post中添加uri参数,也可以在get方式中添加body参数,只是这样做的话,不符合规范,而且很多服务器是按照规范来自定解析方法的,比如:有些服务器会帮你解析,读出body数据,而有些服务器直接忽略,所以,虽然GET可以带request body,但不能保证一定能被接收到。这里有个post和get的区别的文章:https://www.cnblogs.com/logsharing/p/8448446.html 写得很好。

2. Http请求方式

我们知道Restful下常用的几种http请求方式为get、post、put、patch、delete,我们首先要明确一点,http请求方式只是一种约定俗成的规范,因为只要后端对前端发来的get请求做了post该做的事,实际上就是get也完成了post的功能。
正是因为有了这种规范,所以后端开发人员在写不同的api接口时,就要注意自己的方法是否符合当前的http请求方式。比如注册用户这个api,是要创建一个用户到数据库的,这是一个非幂等操作,自然要使用post方式(实际上后端使用get方式也能实现,但是正因为有了这种规范就不推荐使用)。所以归根结底,前后端交互时的http的请求方式,是看我们后端在一定的规范约束之内怎么实现http操作方法,如何定义http路由,如何定义数据交互格式。
下面我们一一来看这几种请求方式。

  1. get 获取资源
  2. post 创建资源
  3. put 创建或更新资源(有则更新,无则创建)
    例如 PUT /items/1 的意思是替换 /items/1 ,存在则替换,不存在则创建。
    所以,PUT方法一般会用来更新一个已知资源。
  4. patch 部分更新资源
  5. delete 删除资源

3.conten-type的不同数据格式及使用注意事项

  1. application/json (在axios中默认的post就是这种格式)
    这个大家很熟悉,就是json格式的数据,在网络流中被编码成json格式的字符串,如:{“key1”:“value1”,“key2”:“value2”}

  2. application/x-www-form-urlencoded
    浏览器的原生 form 表单格式,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码,最终网络流中被编码成类似于这种格式的字符串:title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3

  3. multipart/form-data
    也是浏览器的原生 form 表单格式,与上面不同的是,这个既可以传键值对,也可以用来上传文件。我们使用表单上传文件时,必须让 form 的 enctyped 等于这个值。
    对于其具体格式,我们来看一下它的请求示例:

    POST http://www.example.com HTTP/1.1 
    Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA 
    
    ------WebKitFormBoundaryrGKCBY7qhFd3TrwA 
    Content-Disposition: form-data; name="text" 
    
    title 
    ------WebKitFormBoundaryrGKCBY7qhFd3TrwA 
    Content-Disposition: form-data; name="file"; filename="chrome.png" 
    Content-Type: image/png 
    
    PNG ... content of chrome.png ... 
    ------WebKitFormBoundaryrGKCBY7qhFd3TrwA-- 
    

    实际上对于每一个boundary都是一个键值对,可以包含多种不同的数据类型,可以是text、png
    、二进制文件流等。

所以在进行开发时,要弄清楚我们需要传输的数据到底是什么格式的,比如,如果传的是一个file文件,那么我们的content-type就要为multipart/form-data,如果content-type错误的写为application/json,必然会导致后端解析错误。

//文件上传表单
<form @submit.prevent="upload" method="post" enctype="multipart/form-data">
  <input type="file" name="picture" v-on:change="onChange($event)">
  <button type="submit">上传图片</button>
</form>
//axios处理
var vm = new Vue({
  el: "#vm",
  data: {
    picture: {},
    result: '',
  },

  methods: {
    onChange: function (event) {
      this.picture = event.target.files[0]; // get input file object
      console.log(this.picture);
    },

    upload: function () {
      var that = this;
      var formData = new FormData();
      formData.append('picture', this.picture);
      // specify Content-Type, with formData as well
      this.$http.post('/upload', formData, {
        headers: { 'Content-Type': 'multipart/form-data' } //注意这里要修改请求头的Content-Type属性
      }).then(function (res) {
        res.json().then(function (result) {
          that.result = result.info;
          console.log(that.result);
        });
      }, function (res) {
        console.log(res.body);
      });
    }
  }
});

当然后端也要清楚传过来的是什么格式的数据,对于不同的数据,后端采用的接收数据的方法也不同。比如,如果前端传过来的是一个文件数据,你还是用普通的就收方式处理,那肯定会出错。
一般来说这些后端框架,肯定会有相应的内置文件接收解析对象(或者说是接口-如MultipartFile,暴露给开发人员自定义实现文件对象)。
举个例子,spring中,你需要使用@RequestParam() MultipartFile来接收文件对象,如果你还是使用@RequestBody来进行接收,肯定会出错。

4. 具体应用

先说一下我们网络中基本上传输的都是字符串类型,并不是我们以为的传的是个对象。就拿现今最流行的json来说,前后端在网络交互数据流中,接收到的对方数据并不是json对象,而是一个json格式的字符串,所以前后端都需要对json字符串解析,一般来说,我们会在请求响应的最前端进行拦截并处理。现在许多框架已经在其端点Filter中自动帮我们我们做了这一转换。
现在我们再看一下具体的后端处理前端传参的例子。

先要说明一下,我们要关注的是注解(.net中叫特性)和传参方式(uri传参、body传参)的对应关系,而不是和http请求方式的对应关系。因为http请求方式只是一个数据操作规范,对于这两种传参方式它都可以实现。

比如 .net 中:

  • [FromBody]特性实现处理body体中的数据
  • [FromUri]特性实现处理uri中的查询参数或者路径参数
    其底层是使用媒体格式化程序(MediaTypeFormatter——异步 BufferedMediaTypeFormatter——同步)来接收并解析body中的数据。他们首先根据Content-type来判断所接受的数据类型(比如text/html、application/json等),然后可根据Accept中(text/html,application/xhtml+xml,application/xml)返回固定格式的数据。

再比如spring boot中:

  1. uri参数

    • @PathVariable
      获取路径参数。即url/{id}。
    • @RequestParam
      获取查询参数。即url?name=panda。
    	@GetMapping("/demo/{id}")
    	public void demo(@PathVariable(name = "id") String id, @RequestParam(name = "name") String name) {
    	    System.out.println("id="+id);
    	    System.out.println("name="+name);
    	}
    
  2. Body参数(context-type)

    • @RequestBody
      获取并解析body中的application/json格式数据

      @PostMapping(path = "/demo")
      public void demo1(@RequestBody Person person) {
          System.out.println(person.toString());
      }
      
    • 无注解 或者 @RequestParam
      获取并解析body中的multipart/form-data和x-www-form-urlencoded
      multipart/form-data既可以用做文件数据的传输也可以做键值对的传输(一般做文件传输的时候都要使用这种格式)
      x-www-form-urlencoded只能用做键值对

      @PostMapping(path = "/demo2")
      public void demo2(Person person) {
          System.out.println(person.toString());
      }
      

      SpringMVC通过使用HandlerAdapter 配置的HttpMessageConverters来解析HttpEntity中的数据,然后绑定到相应的bean上

  • 9
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值