使用Filter获取服务器响应内容(字符串)

本文介绍了一种在SpringMVC应用中捕获HTTP响应内容的方法,通过自定义`CustomServletOutputStream`和`CustomHttpServletResponse`类,并结合过滤器实现对输出流的监听,从而可以在不修改业务逻辑的情况下获取到渲染后的页面内容。

spring mvc架构的web应用中,spring框架将数据model渲染至jsp页面并将最终结果输出到客户端,model和jsp模板可以由程序定义,但是页面渲染及结果输出过程是由spring封装,对程序员来说是不可控的。想要取得输出的内容有一种方法就是自定义ServletOutputStream对象,在数据写入至目标流同时写入我们自定义的字节流,通过字节流便可取得输出内容。代码如下:

 

public class CustomServletOutputStream extends ServletOutputStream {

 

    private OutputStream outputStream;

    private ByteArrayOutputStream byteArrayOutputStream;

 

    public CustomServletOutputStream(OutputStream outputStream){

        this.outputStream=outputStream;

        byteArrayOutputStream=new ByteArrayOutputStream();

    }

 

    @Override

    public boolean isReady() {

        return false;

    }

 

    @Override

    public void setWriteListener(WriteListener writeListener) {

 

    }

 

    @Override

    public void write(int b) throws IOException {

        outputStream.write(b);

        byteArrayOutputStream.write(b);

    }

 

    public byte[] getCopy(){

        return byteArrayOutputStream.toByteArray();

    }

}

 

自定义response类为获取字节流数据提供接口

 

public class CustomHttpServletResponse extends HttpServletResponseWrapper {

 

    private ServletOutputStream outputStream;

    private PrintWriter writer;

    private CustomServletOutputStream cout;

 

    /**

     * Constructs a response adaptor wrapping the given response.

     *

     * @throws IllegalArgumentException

     *          if the response is null

     */

    public CustomHttpServletResponse(HttpServletResponse response) {

        super(response);

    }

 

    @Override

    public ServletOutputStream getOutputStream() throws IOException {

        if (writer != null) {

            throw new IllegalStateException("getWriter() has already been called on this response.");

        }

 

        if (outputStream == null) {

            outputStream = getResponse().getOutputStream();

            cout = new CustomServletOutputStream(outputStream);

        }

        return cout;

    }

 

    @Override

    public PrintWriter getWriter() throws IOException {

        if (outputStream != null) {

            throw new IllegalStateException("getOutputStream() has already been called on this response.");

        }

 

        if (writer == null) {

            cout = new CustomServletOutputStream(getResponse().getOutputStream());

            writer = new PrintWriter(new OutputStreamWriter(cout, getResponse().getCharacterEncoding()), true);

        }

        return writer;

    }

 

    @Override

    public void flushBuffer() throws IOException {

        if (writer != null) {

            writer.flush();

        } else if (outputStream != null) {

            cout.flush();

        }

    }

 

    public byte[] getCopy() {

        if (cout != null) {

            return cout.getCopy();

        } else {

            return new byte[0];

        }

    }

}

 

Filter类

 

public class LXCFFilter implements Filter {

 

    @Override

    public void init(FilterConfig filterConfig) throws ServletException {

    }

 

    @Override

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws      IOException, ServletException {

        HttpServletRequest hrequest=(HttpServletRequest)request;

        CustomHttpServletResponse cresponse=new CustomHttpServletResponse((HttpServletResponse)response);

        chain.doFilter(request,cresponse);

//      cresponse.flushBuffer();

        byte[] data=cresponse.getCopy();

        String htmStr=new String(data,response.getCharacterEncoding());

        //do something

        }

 

    @Override

    public void destroy() {

    }

}

 

在web.xml中添加filter

 

    <filter>

        <filter-name>lxcfFilter</filter-name>

        <filter-class>com.gtan.lxcf.common.LXCFFilter</filter-class>

    </filter>

    <filter-mapping>

        <filter-name>lxcfFilter</filter-name>

        <url-pattern>/*</url-pattern>

    </filter-mapping>

 

参考链接 http://stackoverflow.com/questions/8933054/how-to-log-response-content-from-a-java-web-server

<think>好的,用户的问题是如何根据不同的请求字符串配置服务器以返回不同的内容。首先,我需要回忆一下之前提供的引用内容,看看有没有相关的信息可以利用。 引用[2]提到使用Nginx代理时可以通过sub_filter进行字符串替换,但这可能只适用于简单的文本替换,而用户的需求是根据不同的请求参数返回不同内容,可能需要更灵活的处理方式。 引用[3]中的示例代码展示了在Java Servlet中通过request.getParameter("code")获取请求参数,并根据参数值进行处理。这可能是一个方法,即在后端代码中根据参数动态生成响应内容。 引用[4]讨论了SQL Server的配置问题,可能和当前问题关联不大,暂时可以不考虑。 用户的需求可以分为两种情况:前端代理处理和后端动态处理。前端代理比如Nginx可以通过变量匹配请求参数,然后重写请求或直接返回不同内容。后端处理则是在应用程序中解析请求参数,生成对应的响应。 对于前端配置,Nginx的location块可以结合if语句或map模块来匹配查询参数,但需要注意Nginx处理查询参数的限制和性能。例如,使用$arg_变量来获取特定参数的值,然后进行重定向或内容替换。 对于后端处理,比如使用Spring Boot的@RequestParam注解获取参数,然后根据参数值返回不同的数据。这种方法更灵活,适合复杂的业务逻辑。 还需要考虑性能问题,比如缓存策略,避免每次请求都进行复杂的处理。同时,安全性方面要对参数进行验证,防止注入攻击。 另外,用户可能没有明确说明是否需要动态内容生成还是静态内容的映射,但根据问题描述,应该两种情况都涵盖。例如,静态内容可以通过Nginx直接返回不同的文件,动态内容则需要后端逻辑处理。 总结下来,解决方案应该包括前端代理配置和后端逻辑处理两种方法,并比较它们的优缺点,帮助用户选择最适合的方案。同时需要提醒用户注意参数安全性和性能优化。</think>根据不同的请求字符串配置服务器响应内容,可通过以下两种主要方式实现: ### 一、前端代理层配置(以Nginx为例) 1. **根据参数路由请求** ```nginx location /api { # 检查请求参数action的值 if ($arg_action = "create") { proxy_pass http://backend/create; } if ($arg_action = "delete") { proxy_pass http://backend/delete; } } ``` 2. **动态内容替换** 通过`sub_filter`实现响应内容修改(需禁用压缩)[^2]: ```nginx location /docs { sub_filter '原版本' '新版本'; sub_filter_types text/html; proxy_set_header Accept-Encoding ""; } ``` ### 二、后端应用层处理 1. **Java Servlet示例** ```java @RequestMapping("/resource") public String getData(@RequestParam String type) { if ("v1".equals(type)) { return "旧版数据"; } else { return "新版数据"; } } ``` 2. **动态路由配置** ```python # Flask框架示例 @app.route('/api') def handle_request(): mode = request.args.get('mode') if mode == 'simple': return generate_simple_view() elif mode == 'advanced': return generate_advanced_view() ``` ### 三、关键注意事项 1. **参数安全性** - 需验证参数合法性,防止SQL注入和XSS攻击 - 对敏感参数进行加密处理 2. **性能优化** - 对高频请求参数配置缓存策略 - 使用CDN加速静态内容分发 - 动态响应建议保持内容在`maxQueryStringLength`限制内[^1] 3. **调试建议** - 使用Postman进行参数测试 - 监控服务器日志分析请求处理情况
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值