解決在Filter中讀取Request中的流後, 而後再Control中讀取不到的作法

咱們來看一下核心代碼: filter中主要作的事情, 就是來校驗請求是否合法, 是否有篡改過值. java

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

        if (Boolean.valueOf(authentication)) {
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            if (BasicdataCommonsConstant.POST.equalsIgnoreCase(httpServletRequest.getMethod())) {
                // 防止流讀取一次後就沒有了, 因此須要將流繼續寫出去
                ServletRequest requestWrapper = new BodyReaderHttpServletRequestWrapper(httpServletRequest);
                String body = HttpHelper.getBodyString(requestWrapper);
                if (StringUtils.isBlank(body)) {
                    LOGGER.error("非法請求, 沒有APP_KEY, APP_SECRET");
                    OutWriterUtil.outJson(response, gson.toJson(new Response(ErrorCode.AUTH_ERROR_ILLEGAL_FROMTYPE)));
                    return;
                }
                Map<String, String> parameters = gson.fromJson(body, new TypeToken<Map<String, String>>() {
                }.getType());

                String APP_KEY = parameters.get("appKey");
                String APP_SECRET = parameters.get("appSecret");

                TAuthUser authUser = authUserMap.get(APP_KEY);
                if (authUser == null) {
                    LOGGER.error("非法請求, 沒有APP_KEY, APP_SECRET");
                    OutWriterUtil.outJson(response, gson.toJson(new Response(ErrorCode.AUTH_ERROR_ILLEGAL_FROMTYPE)));
                    return;
                } else if (StringUtils.isBlank(APP_SECRET)) {
                    LOGGER.error("非法請求, APP_SECRET爲空, user={}", gson.toJson(authUser));
                    OutWriterUtil.outJson(response, gson.toJson(new Response(ErrorCode.AUTH_ERROR_FROMTYPE_AND_KEY_CANNT_BE_NULL)));
                    return;
                } else if (!APP_SECRET.equals(authUser.getAppSecret())) {
                    LOGGER.error("非法請求: 沒有APP_KEY, APP_SECRET不匹配. user={}, password={}, name={}", APP_KEY, APP_SECRET, authUser.getName());
                    OutWriterUtil.outJson(response, gson.toJson(new Response(ErrorCode.AUTH_ERROR_ILLEGAL_KEY)));
                    return;
                }
                String SIGNATURE = parameters.get("signature");
                // 對參數進行簽名
                String md5 = SignatureUtil.decryptSignature(parameters);
                if (!md5.equals(SIGNATURE)) {
                    LOGGER.error("非法請求, signature ={}", SIGNATURE);
                    OutWriterUtil.outJson(response, gson.toJson(new Response(ErrorCode.AUTH_ERROR_SIGNATURE_ERROR)));
                    return;
                }
                threadLocalUser.setAuthUser(authUser);
                chain.doFilter(requestWrapper, response);
            }
        }
        chain.doFilter(request, response);
    }



你們都知道, 流只能讀一次, 讀了就沒有了, 爲了後面的代碼還可以取得流, 咱們應該還須要將其寫出去才行.

因此, 我新創建了一個類. 看代碼: app

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

/**
 * Created with antnest-platform
 * User: chenyuan
 * Date: 12/31/14
 * Time: 8:49 PM
 */
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {

    private final byte[] body;

    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        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 int read() throws IOException {
                return bais.read();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {

            }
        };
    }
}



import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * Created with antnest-platform
 * User: chenyuan
 * Date: 12/24/14
 * Time: 10:39 AM
 */
public class HttpHelper {

    /**
     * 獲取請求Body
     *
     * @param request
     * @return
     */
    public static String getBodyString(ServletRequest request) {
        StringBuilder sb = new StringBuilder();
        InputStream inputStream = null;
        BufferedReader reader = null;
        try {
            inputStream = request.getInputStream();
            reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String line = "";
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }

}



請注意這裏的編碼, 最好將其轉換成UTF-8的編碼格式, 否則你獲取到的中文則會使亂碼的. 我本身也習慣於UTF-8的編碼.

這樣子就應該差很少了哦~ ide

相關文章
相關標籤/搜索