java doget 和dopost_Servlet中doGet和doPost方法有何区别?

更新内容以下是在公众号中写过一篇文章,更新到这里,方便需要的朋友。

做为一个Web开发者,你一定知道在客户端与服务端的交互中,HTTP协议为我们提供了许多方法可供使用,例如最为大家熟知的GET和POST方法,此外还有PUT和DELETE等。

今天我们就来说说最为大家熟悉,也被误用最多的GET和POST方法,以及GET和POST方法在Tomcat中的处理方式。

1 概念HTTP规范定义

GET方法

The GET method means retrieve whatever information(in the form of an entity) is identified by the Request-URI.

POST方法The POST method is used to request that the origin server accept

the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line.

维基百科定义GETrequests a representation of the specified resource.

POST submits data to be processed (e.g., from an HTML form) to the identified resource.

通过以上的定义说明,我们可以简要概括下:

GET方法用于获取资源

POST方法用于保存与更新资源

(图片取自图解HTTP一书)

2 问题

那为什么说这两个方法被错用了呢,这里错用更多的是指GET方法。看维基百科上除定义之外的附加说明

GETNote that GET should not be used for operations that cause side-effects, such as using it for taking actions in web applications. One reason for this is that

GET may be used arbitrarily by robots or crawlers, which should not need to

consider the side effects that a request should cause.

POSTThe data is included in the body of the request. This may result in the creation

of a new resource or the updates of existing resources or both.

也就是说GET方法不应该被用来做能引起服务端副作用的操作。POST主要用于创建或者更新资源信息

此外,关于GET方法还有一个称呼是幂等(idempotent)方法。

而所谓idempotent,是指无论操作多少次,结果都是一样的。而POST方法,自然不是幂等的,因为他每次都向服务端提交数据,这也是要特别注意表单重复提交的问题。

但开发中,GET方法却为开发人员大量的不分情况的使用。像提交数据,获取信息,删除等等操作。

而大部分应用服务器和Web Server的实现中,都会提供记录accesslog的机制。

这个accesslog会记一些什么呢?下面是tomcat中的GET方法的一条访问记录,我们发现请求中附加的参数也一同被编码记录了下来。

[07/Jan/2016:11:40:50 +0800] "GET /test/servlet?abc=%E4%BD%A0%E5%A5%BD HTTP/1.1" 200 117

而POST方法,log记录下来的只有请求路径而已。

[07/Jan/2016:11:09:11 +0800] "POST /test/servlet HTTP/1.1" 200 127

而这些访问日志在应用中又有可能会提供给第三方的app做统计分析使用,试想,如果如果提交的数据中包含用户名、密码之类的关键信息,那两种方式一对比,就知道该用啥了。

3 对比

GET 请求的一些特点:GET 请求会有 cache

GET 请求会保留在浏览历史中

GET 请求可以保存到书签

GET 请求不应用于处理敏感数据

GET 请求有长度限制

GET 请求应该只用于获取数据

POST 请求的一些特点:POST 不会有cache

POST 请求不会出现在浏览器的浏览历史中

POST 请求不能保存到书签

POST 也是有长度限制的(不同的Web Server可能实现不同)

4 参数处理

那在Tomcat中对于这两种不同的方法中,参数解析是如何处理的呢?依然是我们不变的风格,talk is cheap, 看代码啦!

protected void parseParameters() {

Parameters parameters = coyoteRequest.getParameters();

parameters.setLimit(getConnector().getMaxParameterCount()); //参数个数也是有限制的,默认是10000

parameters.handleQueryParameters(); //如果使用POST方式提交,这里解析不出数据

if( !getConnector().isParseBodyMethod(getMethod()) ) { //这里判断方法是否为POST

return; }

String contentType = getContentType();

if ("multipart/form-data".equals(contentType)) {

parseParts(false); //这里处理文件上传

return; }

if (!("application/x-www-form-urlencoded".equals(contentType))) { //form提交的contentType

return;}

int len = getContentLength();

if (len > 0) {

int maxPostSize = connector.getMaxPostSize();

if ((maxPostSize > 0) && (len > maxPostSize)) {//注意这里对于POST也是有长度限制的,不是一般说的POST不限制,默认是2097152

return; }

if (readPostBody(formData, len) != len) {

return; }

parameters.processParameters(formData, 0, len); //这里的代码在前面的文章中分析过

} else if ("chunked".equalsIgnoreCase(

coyoteRequest.getHeader("transfer-encoding"))) {

formData = readChunkedPostBody(); }

if (formData != null) {

parameters.processParameters(formData, 0, formData.length);

} } }

上面代码中,关键处理部分加了一些注释,无关的代码也都做了删减。参数处理的文章,是公众号里的另一篇,可以后台回复关键字006查看。

protected void service(HttpServletRequest req, HttpServletResponse resp)

throws ServletException, IOException {

String method = req.getMethod();

if (method.equals(METHOD_GET)) {

long lastModified = getLastModified(req);

if (lastModified == -1) {

// servlet doesn't support if-modified-since, no reason // to go through further expensive logic doGet(req, resp);

} else {

long ifModifiedSince;

try {

ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);

} catch (IllegalArgumentException iae) {

// Invalid date header - proceed as if none was set ifModifiedSince = -1;

}

if (ifModifiedSince < (lastModified / 1000 * 1000)) {

// If the servlet mod time is later, call doGet() // Round down to the nearest second for a proper compare // A ifModifiedSince of -1 will always be less maybeSetLastModified(resp, lastModified);

doGet(req, resp);

} else {

resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);

}

}

} else if (method.equals(METHOD_HEAD)) {

long lastModified = getLastModified(req);

maybeSetLastModified(resp, lastModified);

doHead(req, resp);

} else if (method.equals(METHOD_POST)) {

doPost(req, resp);

} else if (method.equals(METHOD_PUT)) {

doPut(req, resp);

} else if (method.equals(METHOD_DELETE)) {

doDelete(req, resp);

} else if (method.equals(METHOD_OPTIONS)) {

doOptions(req,resp);

} else if (method.equals(METHOD_TRACE)) {

doTrace(req,resp);

...

}

我们的Servlet中的doGet和doPost,都是HttpServlet根据不同的请求方法选择调用具体Method对应的逻辑。

理论上,这些不同的y就去设计时是为了对应不同的使用场景,

例如GET,是为了获取资源

POST,则是为了传输实体对象

PUT,为了传输文件

DELETE,为了删除文件

但实际使用的时候,如果你就是要用GET来传一些字段值,也是可以的。但对应的GET方法由于传参数时是添加到URL中,明文显示了出来,可能会有一些问题。

另外,GET和POST两者都是有大小限制的,GET的更小一些。POST的可以通过调整应用服务器接收POST的大小。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值