HttpServletRequest 对象

HttpServletRequest 对象

HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的所有信息。

其他的具体方法就不详细描述了,具体方法上的使用看API,或者网上查查,有很多的。这里就介绍一下 请求方式获取参数 的问题


请求方式

根据HTTP标准,HTTP请求可以使用多种请求方法。

HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。
HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法



其实真正有多少请求方式我具体也没有详细了解过。我在这里就详细介绍一下经常的能接触到的请求.

GET:从服务器取出资源

POST:在服务器新建一个资源

PUT:在服务器更新资源(客户端提供改变后的完整资源)

PACTH:在服务器更新资源(客户端提供改变的属性)

DELETE:从服务器删除资源

OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的


这些接口在遇到服务端是以RESTful风格命名参数的时候是很有用的。这点其实可以参考阮一峰大神的《RESTful API 设计指南》,老实说这里大部分东西也是从那里剽窃来的,有些也加入自己的思考理解,也不知道对不对,说回来,读书人的这种事情能叫做抄吗(原谅我的无耻)。


其他的接口请求都是很好理解的,这里介绍一下OPTIONS,平常好像真的没怎么遇到过这个请求,理解上“获取信息”的请求,有些不知所谓。
其实不是的,遇到最多的请求其实是跨域的情况,在跨域的情况下,浏览器在第一次发送请求之前,会发送一个OPTIONS的请求方式的请求。(当然这里指的是非简单请求)。我们称之为“预检请求”,好了我又想抄了《跨域资源共享 CORS 详解》,阮一峰大神出品(感觉我像死忠粉一样)。

虽然浏览器做了预检请求,但是这时候需要服务端的配合

public class SimpleCORSFilter implements Filter
{

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException
    {
        HttpServletResponse response = (HttpServletResponse) res;  
        response.setHeader("Access-Control-Allow-Origin", "*");  
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");  
        response.setHeader("Access-Control-Max-Age", "3600");  
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Cache-Control, token");
        chain.doFilter(req, res);

    }


    @Override
    public void destroy()
    {
        // TODO Auto-generated method stub

    }


    @Override
    public void init(FilterConfig arg0) throws ServletException
    {
        // TODO Auto-generated method stub

    }

}

需要追加一个这样的过滤器,具体xml配置自行解决吧。

参数解释:

Access-Control-Allow-Origin:

这个Header是用来告诉浏览器,我的这个URL的资源是允许任何来源的请求访问我,如果值是*则表示表示接受任意域名的请求。

Access-Control-Allow-Methods:

顾名思义,表明服务器支持的所有跨域请求的方法。

Access-Control-Max-Age:

用来指定本次预检请求的有效期,单位为秒。在上面的设置中,即允许缓存该条回应为3600秒,在此期间不用发出另一条预检请求。

Access-Control-Allow-Headers:

表明服务器支持的所有头信息字段,不限于浏览器在”预检”中请求的字段。原文:The Access-Control-Allow-Headers header is used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.

这里是关于跨域请求的事情了,扯远了。


Request请求在body体中获取参数

在Request请求获取参数的方式多种多样
这里我就给几个链接吧《Spring Controller 获取请求参数的几种方法》,《springmvc请求参数获取的几种方法》



这里想要说明一下request.getParameter(),request.getInputStream(),request.getReader()中request.getInputStream(),request.getReader()这两种方式。

这两个方法都是将request当做一个流对象来获取数据,区别呢是getInputStream 字节流得到的对象是InputStream对象,如果里边有二进制的话只能用这个读,getReader 字符流得到的是Reader对象,会按照请求消息中指定的字符集编码转换成文本字符串。 对于对于流来说我们可以把他们理解成管道,既然是管道,那么只能读取一次,第一次读取的时候可以读取到数据,但是接下来的读取操作都读取不到数据。

原因:

1 . 一个InputStream对象在被读取完成后,将无法被再次读取,始终返回-1;
2 . InputStream并没有实现reset方法(可以重置首次读取的位置),无法实现重置操作;


解决方法

1.使用request、session等来缓存读取到的数据,这种方式很容易实现,只要setAttribute和getAttribute就行(但是这样写未免太不优雅了);

2.使用HttpServletRequestWrapper来包装HttpServletRequest,在MAPIHttpServletRequestWrapper中初始化读取request的InputStream数据,以byte[]形式缓存在其中,然后在Filter中将request转换为包装过的request(强烈推荐如下放大);代码如下:

重写request

public class MAPIHttpServletRequestWrapper extends HttpServletRequestWrapper {  

    private final byte[] body; // 报文  

    public MAPIHttpServletRequestWrapper(HttpServletRequest request) throws IOException {  
        super(request);  
        body = StreamUtil.readBytes(request.getInputStream());  
    }  

    @Override  
    public BufferedReader getReader() throws IOException {  
        return new BufferedReader(new InputStreamReader(getInputStream()));  
    }  

    @Override  
    public ServletInputStream getInputStream() throws IOException {  
        final ByteArrayInputStream bais = new ByteArrayInputStream(body);  
        return new ServletInputStream() {  

            @Override  
            public int read() throws IOException {  
                return bais.read();  
            }  
        };  
    }  

}  

配置相应过滤器

public class HttpServletRequestReplacedFilter implements Filter {  

    @Override  
    public void destroy() {  

    }  

    @Override  
    public void doFilter(ServletRequest request, ServletResponse response,  
            FilterChain chain) throws IOException, ServletException {  
        ServletRequest requestWrapper = null;    
        if(request instanceof HttpServletRequest) {    
            requestWrapper = new MAPIHttpServletRequestWrapper((HttpServletRequest) request);    
        }    
        if(requestWrapper == null) {    
            chain.doFilter(request, response);    
        } else {    
            chain.doFilter(requestWrapper, response);    
        }    
    }  

    @Override  
    public void init(FilterConfig arg0) throws ServletException {  

    }  

}  

最后注意 request.getParameter()、 request.getInputStream()、request.getReader()这三种方法是有冲突的,因为流只能被读一次。
比如:

当form表单内容采用 enctype=application/x-www-form-urlencoded编码时,先通过调用request.getParameter() 方法得到参数后,再调用 request.getInputStream()或request.getReader()已经得不到流中的内容,因为在调用 request.getParameter()时系统可能对表单中提交的数 据以流的形式读了一次,反之亦然。

当form表单内容采用 enctype=multipart/form-data编码时,即使先调用request.getParameter()也得不到数据,但是这时调用 request.getParameter()方法对 request.getInputStream()或request.getReader()没有冲突,即使已经调用了 request.getParameter()方法也 可以通过调用request.getInputStream()或request.getReader()得 到表单中的数据,而request.getInputStream()和request.getReader()在同 一个响应中是不能混合使用的,如果混合使用就会抛异常。
此处参考了

https://www.cnblogs.com/v5hanhan/p/5646054.html

https://www.cnblogs.com/fzng/p/7227787.html?utm_source=itdadao&utm_medium=referral

转载于:https://www.cnblogs.com/liyunq/p/9724605.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值