SpringMVC/SpringBoot下restful风格URL,以及Http method的选择、传值问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/flyfeifei66/article/details/82899421

一、Http 请求方法

HTTP/1.1 协议规定的 HTTP 请求方法有 OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 8种,常用的有GET DELETE POST PUT四种。这些方法最大的区别是语义的区别,分别代表获取、删除、增加、修改操作,引导对资源的操作使用对应的方法。用法上也略有区别,常用的四种方法中又以GET、POST最为常用。

1.1 DELETE 和PUT不常用的原因

  • 历史原因

     HTTP1.0只定义了三种请求方法: GET、POST 和 HEAD方法,没有DELETE和PUT,导致很多旧的浏览器、WEB中间件不支持DELETE和PUT,我经过测试发现,新版本的浏览器、WEB服务器早就支持了。

  • 企业的安全策略

     有些企业为了安全,采用了些安全措施,比如安装了防火墙,阻止DELETE、PUT请求。我们知道其实安不安全跟这个method关系不大。

  • 其他,可能还有很多原因

    restful风格的URL建议我们根据操作意图使用对应的method, 但是为了有更好的兼容性,我们使用GET和POST两种方式

1.2 GET和POST的区别

  • GET传值只能通过URL,POST方式URL可以带参数,请求体中也可以带参数。
  • GET传值,URL长度有限制,POST请求体几乎无限制。
  • GET适合传少量值,POST适合传递大量值,由于带请求体,请求头必须带有contentType,GET请求头没有Content-Type。axiosGET方式,即便手动设置Content-Type,也会被忽略(这篇文章有介绍)。
  • 注意,有些说法说GET不安全、POST安全纯属以讹传讹,安不安全跟用什么method没有关系,安全的HTTP是HTTPS,否则HTTP信息就是裸露在网上的。

二、Content-Type

是什么?Content-Type是http请求的头信息,但不是所有的方法都有。比如GET就没有,POST有。它用来告诉服务器本次请求体的数据格式是什么。

服务端是根据请求头(headers)中的 Content-Type 字段来获知请求中的消息主体是用何种格式,再对主体进行解析,SpringMVC是由类HttpMessageConverter完成解析的,可以参考这篇文章理解,这里只介绍几种常见的类型。

  • application/x-www-form-urlencoded

浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。请求类似于下面这样(无关的请求头在本文中都省略掉了):

POST http://www.example.com HTTP/1.1      // 这里是请求行
Content-Type: application/x-www-form-urlencoded;charset=utf-8  //这里是请求头
title=test&myword=%E6%89%8B%E6%9C%BA   //这里是请求

首先,Content-Type 被指定为 application/x-www-form-urlencoded;其次,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。

  • multipart/form-data

这又是一个常见的 POST 数据提交的方式。我们使用表单上传文件时,必须让 form 的 enctyped 等于这个值。它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来表名文件类型;content-disposition,用来说明字段的一些信息; 参考这篇文章

  • application/json

application/json 这个 Content-Type 作为响应头大家肯定不陌生。实际上,现在越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。

json的好处体积小,比XML小太多、与JS交互方便,解析难度小(几乎为0),最重要的是灵活,特别是在传输层次结构比较复杂的数据时,正成为一代数据传输利器。

一个示例如下

POST http://www.example.com HTTP/1.1
Content-Type: application/json;charset=utf-8
 
{"title":"test","sub":[1,2,3]}
  • text/xml

XML-RPC(XML Remote Procedure Call)。它是一种使用 HTTP 作为传输协议,XML 作为编码方式的远程调用规范。典型的 XML-RPC 请求是这样的:

POST http://www.example.com HTTP/1.1
Content-Type: text/xml
 
<!--?xml version="1.0"?-->
<methodcall>
    <methodname>examples.getStateName</methodname>
    <params>
        <param>
            <value><i4>41</i4></value>
         
    </params>
</methodcall>

XML-RPC 协议简单、功能够用,各种语言的实现都有。它的使用也很广泛,如 WordPress 的 XML-RPC Api。JavaScript 中,也有现成的库支持以这种方式进行数据交互,能很好的支持已有的 XML-RPC 服务。不过,我个人觉得 XML 结构还是过于臃肿,一般场景用 JSON 会更灵活方便。

XML是体积太过庞大,个人认为正在被JSON取代,不予考虑。

2.1 HTTP接口入参类型选择

POST请求(非文件上传)使用JOSN作为数据传输格式,参考各大互联网公司,在微服务的时代,他们对外提供的HTTP接口都是HTTP+JSON。使用JOSN还有一个好处,它的结构非常好,能精确的描述接口协议,XML在这方面则更胜一筹,传统的xform最差。

2.2 HTTP接口返回值类型选择

排除XML,只剩下HTML文本、json和自定义格式的文本。采用前后端分离技术,HTML文本也被排除,json为不二之选。

拓展:一个返回json中,除了正常的业务数据,还应该包含状态码、以及对应的Msg,参考dubbo的最佳实践。调用方在获取到返回值后首先应该判断状态码。因此后台设计api时,返回值应该使用一个DTO定义,此DTO继承一个父类,父类包含状态、Msg。方法使用@ResponseBody注解,SpringMVC会自动转换为json输出。

同理,入参也应该使用DTO定义,使用@RequestBody注解,只要前台传递的json各个字段跟入参bean的字段对应,SpringMVC会自动转化赋值。

三、springmvc常用传值方式

  • GET请求,URL传参,比例xxx/yyy?id=001,后台使用@RequestParam接收参数。
  • GET请求,URI传参,比如xxx/yyy/id,后台@RequestMapping配置value=xxx/yyy/{id},形参使用注解@PathVariable接收参数
  • POST请求,请求体为JOSN,后台形参使用注解@RequestBody接收参数
  • POST请求,请求体为FROM,后台形参使用注解@ModelAttribute接收参数

四、restful风格的URL

restful只是url的一种风格,最佳实践可以参考这里。

风格精髓:url代表资源(貌似url的定义本就是如此),method代表操作意图,url简短、优雅。

 

 

那么在SpringMVC下,如果要使用restful的URL,具体该怎么做?需要综合考虑http method、contentType、传值方式。

我们看到最佳实践中有些url是相同的,只是method不同,这在后台不是很好处理。参考微信公众号的api,我们总结出自己的实践如下,使得URL接近restful,以user管理为例。

场景 http method URL contentType 传值方式 说明
获取一个资源 get user/(get|info)/id -- url路径传值  
获取资源列表 get user/(list) -- url传值 适合无参获取列表。参数较少时也可使用user/list?形式
获取资源列表 post user/(list) json post请求体 适合参数较多(比如分页查询,不仅要传分页信息,还要穿搜索条件),这是一个妥协方式。
新增一个资源 post user/(add|create) json post请求体  
修改一个资源 post user/(update/modify)/id json post请求体  
删除一个资源 get user/(delete|remove)/id -- url路径传值  

也就是说,  获取数据(语义上就是get)和传值较少(delete)使用get方式,优先使用url路径传值,而后考虑url参数传值。

传值较多(新增、修改,分页查询)使用post,数据格式为json,其他格式不允许。

文件操作另行设计。

五、后台相关(Controller)

  • restful风格的url没有.后缀,如果springmvc DispatcherServlet配置拦截了带有后缀的部分需要去掉,改为<url-pattern>/</url-pattern>。(可以通过配置不拦截的静态资源类型达到只拦截获取数据URL的目的)
  • 不管get和post方法,@RequestMapping 除了value和method外,必须配置produces = "application/json;charset=UTF-8",用来告知客户端返回值为json,虽然有些客户端api有设置返回值类型。这里可以设置charset用来防止中文乱码,否则可能会出现客户端能解析但是中文乱码。
  • consumes标示本接口希望接收的参数的格式,对应http请求头的content-type。springmvc在解析数据时会做对比校验。post方法一定要写用来明确表示。get方法一定不要写,因为get没有content-type,写了就会校验报错,错误为 不支持' ',这个空字符串就是因为没有获取到content-type。

猜你喜欢

转载自blog.csdn.net/flyfeifei66/article/details/82899421