HTTP的请求方法:GET、POST、PUT和DELETE

一、 HTTP方法

HTTP定义了与服务器交互的不同方法,最基本的方法有4种,分别是GET,POST,PUT,DELETE。URL全称是资源描述符,我们可以这样认为:一个URL地址,它用于描述一个网络上的资源,而HTTP中的GET,POST,PUT,DELETE就对应着对这个资源的查,增,改,删4个操作,GET一般用于获取/查询资源信息,而POST一般用于创建资源,PUT一般用于更新资源信息。

1. GET方法

根据HTTP规范,GET用于信息获取,而且应该是安全的和幂等的。

所谓安全的意味着该操作用于获取信息而非修改信息。换句话说,GET 请求一般不应产生副作用。就是说,它仅仅是获取资源信息,就像数据库查询一样,不会修改,增加数据,不会影响资源的状态。

幂等的意味着对同一URL的多个请求应该返回同样的结果。

使用方式:GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,参数之间以&相连,如:login.action?name=hyddd& password=idontknow&verify=%E4%BD%A0%E5%A5%BD。如果数据是英文字母/数字,原样发送,如果是空 格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密,得出如:%E4%BD%A0%E5%A5%BD,其中%XX中的XX为该符号以 16进制表示的ASCII。

长度限制:因为GET是通过URL提交数据,那么GET可提交的数据量就跟URL的长度有直接关系了。而实际上,URL不存在参数上限的问题,HTTP协议规范没有对URL长度进行限制。这个限制是特定的浏览器及服务器对它的限制。IE对URL长度的限制是2083字节(2K+35)。对于其他浏览器,如Netscape、FireFox等,理论上没有长度限制,其限制取决于操作系统的支持。注意这是限制是整个URL长度,而不仅仅是你的参数值数据长度。

安全性:通过GET提交数据,用户名和密码将明文出现在URL上,因为(1)登录页面有可能被浏览器缓存,(2)其他人查看浏览器的历史纪录,那么 别人就可以拿到你的账号和密码了,除此之外,使用GET提交数据还可能会造成Cross-site request forgery攻击。

2. POST方法

根据HTTP规范,POST表示可能修改变服务器上的资源的请求。

使用方式:POST把提交的数据则放置在是HTTP包的包体中。

长度限制:POST是没有大小限制的,HTTP协议规范也没有进行大小限制,说“POST数据量存在80K/100K的大小限制”是不准确的,POST数据是没有限制的,起限制作用的是服务器的处理程序的处理能力。

安全性:POST的安全性要比GET的安全性高。

3. 新增数据操作应该使用post还是put?

根据幂等性idempotent确认。参考:post和put的区别

幂等性概念:幂等通俗来说是指不管进行多少次重复操作,都是实现相同的结果。

GET,PUT,DELETE都是幂等操作,而POST不是,以下进行分析:

首先GET请求很好理解,对资源做查询多次,此实现的结果都是一样的。 
PUT请求的幂等性可以这样理解,将A修改为B,它第一次请求值变为了B,再进行多次此操作,最终的结果还是B,与一次执行的结果是一样的,所以PUT是幂等操作。 
同理可以理解DELETE操作,第一次将资源删除后,后面多次进行此删除请求,最终结果是一样的,将资源删除掉了。

POST不是幂等操作,因为一次请求添加一份新资源,二次请求则添加了两份新资源,多次请求会产生不同的结果,因此POST不是幂等操作。

了解REST后很长一段时间不能明确区分PUT和POST的区别,在使用时很容易混淆,完全可根据idempotent(幂等性)做区分。

举一个简单的例子,假如有一个博客系统提供一个Web API,模式是这样http://superblogging/blogs/{blog-name},很简单,将{blog-name}替换为我们的blog名字,往这个URI发送一个HTTP PUT或者POST请求,HTTP的body部分就是博文,这是一个很简单的REST API例子。我们应该用PUT方法还是POST方法?

取决于这个REST服务的行为是否是idempotent的,假如我们发送两个http://superblogging/blogs/post/Sample请求,服务器端是什么样的行为?如果产生了两个博客帖子,那就说明这个服务不是idempotent的,因为多次使用产生了副作用了嘛;如果后一个请求把第一个请求覆盖掉了,那这个服务就是idempotent的。前一种情况,应该使用POST方法,后一种情况,应该使用PUT方法。

二、方法测试

可通过浏览器插件或postman等专用工具测试。

1. 浏览器插件

如果是GET请求,测试起来非常简单:只需要在浏览器地址栏里拼就可以了
比如:
GET /blog/?name1=value1&name2=value2 HTTP/1.1
Host: carsonified.com

但对于POST(以及DELETE和PUT)请求,测试起来没那么直接,需要放到HTTP Message Body里。
比如:
POST /blog/ HTTP/1.1
Host: carsonified.com
name1=value1&name2=value2

所以就有了一些浏览器插件作为辅助。

对于Firefox,有一个叫REST Client的(https://addons.mozilla.org/zh-cn/firefox/addon/restclient/)。

对于Chrome,是叫Advanced REST Client(https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo/reviews)。直接在Chrome Store里下载就行。建议挂VPN装。因为装完后会从某个blogspot下载个更新,如果没挂VPN的话会被墙,没法更新。

2. Postman

postman支持5中body:none,form-data,x-www-form-urlencoded,raw,binary。

1) form-data: 就是http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来表名文件类型;content-disposition,用来说明字段的一些信息。由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对。

参考:rfc2388的multipart/form-data

 

form-data格式下不要设置headers,应用会自适应。

You shouldNEVERset that header yourself. We set the header properly with the boundary. If you set that header, we won't and your server won't know what boundary to expect

(since it is added to the header). Remove your custom Content-Type header and you'll be fine.

2) x-www-form-urlencoded就是application/x-www-from-urlencoded,会将表单内的数据转换为键值对,比如,name=java&age = 23

3) raw:可以上传任意格式的文本,可以上传text、json、xml、html等

4) binary:相当于Content-Type:application/octet-stream,从字面意思得知,只可以上传二进制数据,通常用来上传文件,由于没有键值,所以,一次只能上传一个文件。

备注:multipart/form-data与x-www-form-urlencoded区别

multipart/form-data:既可以上传文件等二进制数据,也可以上传表单键值对,只是最后会转化为一条信息。

 x-www-form-urlencoded:只能上传键值对,并且键值对都是间隔分开的。

三、 linux下HTTP方法实现

1. wget

wget -O -  "http://$IP/host" --header="Content-Type: application/json" --post-data "{ \"challange\": \"$challange\", \"token\": \"$token\", \"mac\": { $mac } }"     ;输出到标准输出

2. curl

curl -i -k -H "Content-type: application/json" -X POST -d '{"version":"6.6.0", "from":"mu", "product_version":"1.1.1.0"}' https://10.10.10.10:80/test

curl -X PUT -d '[{"Min_Int8": "0", "Max_Int8": "10"}]' http://localhost:48082/api/v1/device/5cbede329f8fc20001d68297/command/5cbede329f8fc20001d68292

curl --unix-socket /var/run/docker.sock -X GET http:/containers/64c13a583880/stats

curl --unix-socket /var/run/docker.sock -X GET http:/containers/64c13a583880/stats?stream=false

利用libcurl库可实现HTTP方法:

01Linux下使用libcurl(C语言)来实现http请求(数据保存至文件)(包括下载libcurl)

HTTP多线程下载+断点续传(libcurl库)

3. nc

echo -e "GET /containers/[CONTAINER_NAME]/stats HTTP/1.0\r\n" | nc -U /var/run/docker.sock
echo -e "GET /containers/64c13a583880/stats HTTP/1.0\r\n" | nc -U /var/run/docker.sock

4. C语言实现get和post

 

参考:

1. linux C 实现HTTP get 及post 请求

2. Linux命令发送Http的get或post请求

3. HTTP请求中POST与GET的区别 

4. RESTful

5. Http中Content-Type的取值讲解

posted @ 2018-08-25 19:45  yuxi_o  阅读(3946)  评论(0编辑  收藏  举报