返回顶部
首页 > 资讯 > 后端开发 > Python >如何构建可重复读取inputStream的request
  • 918
分享到

如何构建可重复读取inputStream的request

2024-04-02 19:04:59 918人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

目录构建可重复读取inputStream的requestrequest中inputStream多次读取原因解决方法(缓存读取到的数据)代码构建可重复读取inputStream的req

构建可重复读取inputStream的request

我们知道,request的inputStream只能被读取一次,多次读取将报错,那么如何才能重复读取呢?答案之一是:增加缓冲,记录已读取的内容。

代码如下所示:

import lombok.extern.log4j.Log4j2;
import org.springframework.mock.WEB.DelegatingServletInputStream;
import javax.servlet.ServletInputStream;
import javax.servlet.Http.httpservletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;

@Log4j2
public class RepeatedlyReadRequestWrapper extends HttpServletRequestWrapper {
    private static final int BUFFER_START_POSITION = 0;
    private static final int CHAR_BUFFER_LENGTH = 1024;
    
    private final String body;
    
    public RepeatedlyReadRequestWrapper(HttpServletRequest request) {
        super(request);
        StringBuilder stringBuilder = new StringBuilder();
        InputStream inputStream = null;
        try {
            inputStream = request.getInputStream();
        } catch (IOException e) {
            log.error("Error reading the request body…", e);
        }
        if (inputStream != null) {
            try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
                char[] charBuffer = new char[CHAR_BUFFER_LENGTH];
                int bytesRead;
                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, BUFFER_START_POSITION, bytesRead);
                }
            } catch (IOException e) {
                log.error("Fail to read input stream",e);
            }
        } else {
            stringBuilder.append("");
        }
        body = stringBuilder.toString();
    }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
        return new DelegatingServletInputStream(byteArrayInputStream);
    }
}

接下来,需要一个对应的Filter.

代码如下所示:

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class RepeatlyReadFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //Do nothing
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        if (request instanceof HttpServletRequest) {
            request = new RepeatedlyReadRequestWrapper((HttpServletRequest) request);
        }
        chain.doFilter(request, response);
    }
    @Override
    public void destroy() {
        //Do nothing
    }
}

最后,需要在web.xml中,增加该Filter的配置(略)。 

request中inputStream多次读取

在使用HTTP协议实现应用间接口通信时,服务端读取客户端请求过来的数据,会用到request.getInputStream(),第一次读取的时候可以读取到数据,但是接下来的读取操作都读取不到数据。

原因

一个InputStream对象在被读取完成后,将无法被再次读取,始终返回-1;

InputStream并没有实现reset方法(可以重置首次读取的位置),无法实现重置操作;

解决方法(缓存读取到的数据)

使用request、session等来缓存读取到的数据,这种方式很容易实现,只要setAttribute和getAttribute就行;

使用HttpServletRequestWrapper来包装HttpServletRequest,在中初始化读取request的InputStream数据,以byte[]形式缓存在其中,然后在Filter中将request转换为包装过的request;

代码

编写rHttpServletRequestWrapper子类,用来处理请求数据


import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.NIO.charset.Charset;
import java.util.Enumeration;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper
{
	private final byte[] body;
	public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException
	{
		super(request);
		Enumeration<String> e = request.getHeaderNames();
		while (e.hasMoreElements())
		{
			String name = (String) e.nextElement();
			String value = request.getHeader(name);
			log.debug("HttpServletRequest头信息:{}-{}", name, value);
		}
		body = HttpHelper.getBodyString(request).getBytes(Charset.forName("UTF-8"));
	}
	@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 boolean isFinished()
			{
				return false;
			}
			@Override
			public boolean isReady()
			{
				return false;
			}
			@Override
			public void setReadListener(ReadListener listener)
			{
				
			}
			@Override
			public int read() throws IOException
			{
				return bais.read();
			}
			
		};
		
	}
	@Override
	public String getHeader(String name)
	{
		return super.getHeader(name);
	}
	@Override
	public Enumeration<String> getHeaderNames()
	{
		return super.getHeaderNames();
	}
	@Override
	public Enumeration<String> getHeaders(String name)
	{
		return super.getHeaders(name);
	}
}

调用

public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException
	{
		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;
		
		ServletRequest requestWrapper = null;
		requestWrapper = new BodyReaderHttpServletRequestWrapper(httpRequest);
		
		//数据读取处理
		//...
		//将requestWrapper专递给后面的过滤器
		filterChain.doFilter(requestWrapper, httpResponse);
	}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

--结束END--

本文标题: 如何构建可重复读取inputStream的request

本文链接: https://lsjlt.com/news/142541.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 如何构建可重复读取inputStream的request
    目录构建可重复读取inputStream的requestrequest中inputStream多次读取原因解决方法(缓存读取到的数据)代码构建可重复读取inputStream的req...
    99+
    2024-04-02
  • 怎么构建可重复读取inputStream的request
    本篇内容介绍了“怎么构建可重复读取inputStream的request”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!构建可重复读取inpu...
    99+
    2023-06-29
  • Springboot如何设置过滤器及重复读取request里的body
    目录HttpServletRequest的输入流只能读取一次的原因重复读取body中数据的方法springboot的过滤器上面的getBody的代码需求: request的conte...
    99+
    2024-04-02
  • SpringBoot v2.2以上重复读取Request Body内容的解决方案
    目录SpringBootv2.2以上重复读取RequestBody内容一、需求二、解决方案三、遇到问题四、问题排查解决方案SpringBoot读取Request参数的坑后端拿参数相关...
    99+
    2024-04-02
  • jmeter如何读取json重复数据
    要在JMeter中读取重复的JSON数据,您可以使用以下步骤:1. 添加一个HTTP请求,用于获取返回的JSON数据。2. 添加一个...
    99+
    2023-09-15
    jmeter json
  • 函数拼图:构建灵活、可重复使用的代码
    函数拼图的概念 函数拼图是一种软件开发技术,将复杂代码分解为较小的、可重用的函数。每个函数执行特定任务,并与其他函数相互协作以完成更大的目标。通过这种方式,您可以创建易于理解、修改和维护的代码。 函数拼图的好处 函数拼图提供了以下主要好...
    99+
    2024-03-02
    函数拼图、代码重用、模块化代码、可读性、可维护性
  • ASP中的类:揭秘如何构建可重用代码之谜
    在ASP中,类是一种强大的工具,可用于构建可重用代码,实现软件模块化,并提高开发效率。通过使用类,您可以将数据和行为组织成逻辑单元,并通过对象实例化类来创建具有相同数据和行为的新实体。 一、创建类 在ASP中创建类非常简单,您只需要使用...
    99+
    2024-02-26
    ASP、类、面向对象编程、代码重用、继承、演示代码
  • Gateway网关自定义拦截器的不可重复读取数据问题
    目录Gateway网关自定义拦截器的不可重复读取数据统一网关Gateway一、为什么需要网关二、搭建网关服务三、路由断言工厂四、路由过滤器五、跨域问题处理Gateway网关自定义拦截...
    99+
    2024-04-02
  • PHP和Git:如何利用Composer和Packagist构建可重用的代码库?
    在现代的软件开发中,构建可重用的代码库已经成为了一项非常重要的任务。这不仅可以提高开发效率,还可以降低代码维护成本。在PHP开发中,Composer和Packagist是两个非常流行的工具,可以帮助我们构建可重用的代码库。在本文中,我们将...
    99+
    2023-07-24
    load laravel git
  • 如何读取具有结构地址的接口值
    在Go语言中,接口是一种非常强大和灵活的类型。然而,当我们尝试读取一个接口值中的结构地址时,可能会遇到一些困惑。那么,如何读取具有结构地址的接口值呢?在本文中,我们将为您解答这个问题,...
    99+
    2024-02-10
    go语言 overflow
  • mysql中如何获取不重复的数据
    这篇文章主要介绍mysql中如何获取不重复的数据,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!在mysql中,可以在查询语句中添加distinct关键字来来过滤重复的记录,获取不重复...
    99+
    2024-04-02
  • java如何取出list里重复的元素
    可以使用两层循环遍历list,对每个元素进行比较,如果找到重复的元素,则将其添加到一个新的list中。以下是一个示例代码:```ja...
    99+
    2023-09-11
    java
  • oracle如何只取一条重复的数据
    oracle只取一条重复的数据的步骤:1、使用SELECT语句结合GROUP BY和HAVING子句来查找重复数据;2、使用ROWID删除重复数据,可以确保删除的是精确的重复数据记录,或者使用“ROW_NUMBER()”函数...
    99+
    2023-07-10
  • 如何创建可复用的 Golang 函数?
    go 中创建可复用函数的三步方法:1. 定义函数:使用 func 关键字,指定函数名称、参数类型和返回值类型;2. 函数签名:包含函数名称和参数类型;3. 函数体:包含函数逻辑,使用参数...
    99+
    2024-04-19
    函数 golang
  • 如何创建可重用的 C++ 函数模板?
    函数模板可用于创建可适用于多种数据类型的函数,只需指定使用的类型即可,从而节省时间并减少重复代码。具体步骤如下:使用指定数据类型。指定返回类型。命名函数。指定参数列表。 如何创建可重用...
    99+
    2024-04-15
    c++ 函数模板
  • 如何在 PHP 中创建可重用的函数?
    在 php 中创建可重用的函数的步骤包括:使用 function 关键字定义函数。通过函数名和参数调用函数。使用默认参数以省略某些参数。将函数作为参数传递给其他函数(高阶函数编程)。实战...
    99+
    2024-04-10
    函数 php
  • 如何使用 PHP 创建可重用的组件
    php 组件为代码重用提供了模块化块。创建组件涉及创建一个包含逻辑和功能的类并将其注册到自动加载器中。组件通过其类使用,例如一个计算销售税的组件。实战案例展示了使用组件在电子商务应用程序...
    99+
    2024-05-01
    组件 php composer
  • php如何提取数组中不重复的值
    今天小编给大家分享一下php如何提取数组中不重复的值的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。提取步骤:1、利用arra...
    99+
    2023-07-02
  • 如何构建一个可测试的Go Web应用
    如何构建一个可测试的Go Web应用,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。几乎每一个程序员都赞同测试是重要的,但测试以多种方式让写...
    99+
    2024-04-02
  • 微服务架构中如何处理服务的可维护性和可读性?
    在当前的软件开发中,微服务架构已经逐渐成为了一个关注的焦点。微服务架构是指将应用程序拆分成多个小型的服务,并且每个服务都可以独立部署和运行。这种架构风格可以提高应用程序的可扩展性和可靠性,但也会带来新的挑战。其中最重要的挑战之一就是如何处理...
    99+
    2023-05-16
    微服务架构 可维护性 可读性
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作