天天看點

Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法

文章目錄

  • 前言
  • 一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊
  • 二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、
  • 三、另一個發現:
  • 四、解決方法

前言

一次SpringCloud Zuul的使用中,發現擷取請求參數requestParam總是為null,遂進行了一次簡單源碼跟蹤

一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊

Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  1. org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration 中配置了一個 org.springframework.cloud.netflix.zuul.web.ZuulController
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  2. ZuulController繼承了org.springframework.web.servlet.mvc.ServletWrappingController

    而ZuulController的構造器中,調用了方法 setServletClass(ZuulServlet.class)

    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  3. ZuulControlle同時重寫了Spring-webmvc ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception; 方法
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  4. 在netflix提供的com.netflix.zuul.http.ZuulServlet中,執行個體化了一個 ZuulRunner
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  5. 而ZuulServlet本質上是一個Servlet,容器會調用init方法,進而調用ZuulRunner的 init方法
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  6. 該方法中調用了 Requecom.netflix.zuul.context.RequestContext的setRequest()方法(zuul的上下文封裝,本質是一個map)
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  7. 而當一個請求進入zuulServlet後,會調用servlet的service()方法,這裡是所有類型的ZuulFilter的調用
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  8. 這裡我們隻看preRoute() 方法,其他同理。可以看到,其實是調用了 zuulRunner的preRoute()方法
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  9. 接着調用com.netflix.zuul.FilterProcessor的preRoute方法,
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  10. 可以看到,這裡擷取了所有類型為pre的過濾器
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  11. 調用processZuulFilter(zuulFilter)方法
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  12. 執行filter的runFilter方法,繼而調用了 每個filter重寫的run()方法
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  13. 進入我們自己實作的ZuulFilter功能代碼
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法

二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、

  1. 首先看下 RequestContext.getRequestQueryParams()方法,其實是調用ConcurrentHashMap的get(key)方法(上面說過RequestContext本質是map)
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  2. 這裡走自己的過濾器,直接擷取requestParam為null,可以看到取得的 RequestContext 中并沒有名稱為requestQueryParams的key,并且上下文中存放的request是一個org.springframework.cloud.netflix.zuul.filters.pre.Servlet30RequestWrapper的包裝類
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  3. 我們繼續往下走,擷取Servlet30RequestWrapper對象并調用他的getParameterMap方法,而Servlet30RequestWrapper繼承了com.netflix.zuul.http.HttpServletRequestWrapper,最終調用的是HttpServletRequestWrapper的getParameterMap()方法
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  4. 進入parseRequest()方法,我們發現又進入了HTTPRequestUtils.getInstance().getQueryParams()這個方法調用
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  5. 而在HTTPRequestUtils.getQueryParams()這個方法的最後,調用了上下文的setRequestQueryParams()方法
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  6. 可以看到這裡才真正把requestQueryParams這個key與value put進上下文這個map裡面
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法
  7. 現在 再使用上下文獲requestQueryParams 時,就可以擷取requestParam了
    Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法

三、另一個發現:

在org.springframework.cloud.netflix.zuul.filters.pre.Servlet30RequestWrapper#getRequest中

Zuul擷取queryParams為null,源碼分析前言一、SpringCloud中,zuul的相關配置類與功能接入類,以及部分調用鍊二、記一次 使用 Zuul的 RequestContext擷取RequestParameters為null的情況、三、另一個發現:四、解決方法

四、解決方法

在過濾器中直接使用

即可獲得requestParam

這裡貼上getQueryParams的源碼

/**
     * returns query params as a Map with String keys and Lists of Strings as values
     * @return
     */
    public Map<String, List<String>> getQueryParams() {

        Map<String, List<String>> qp = RequestContext.getCurrentContext().getRequestQueryParams();
        if (qp != null) return qp;

        HttpServletRequest request = RequestContext.getCurrentContext().getRequest();

        qp = new LinkedHashMap<String, List<String>>();

        if (request.getQueryString() == null) return null;
        StringTokenizer st = new StringTokenizer(request.getQueryString(), "&");
        int i;

        while (st.hasMoreTokens()) {
            String s = st.nextToken();
            i = s.indexOf("=");
            if (i > 0 && s.length() >= i + 1) {
                String name = s.substring(0, i);
                String value = s.substring(i + 1);

                try {
                    name = URLDecoder.decode(name, "UTF-8");
                } catch (Exception e) {
                }
                try {
                    value = URLDecoder.decode(value, "UTF-8");
                } catch (Exception e) {
                }

                List<String> valueList = qp.get(name);
                if (valueList == null) {
                    valueList = new LinkedList<String>();
                    qp.put(name, valueList);
                }

                valueList.add(value);
            }
            else if (i == -1)
            {
                String name=s;
                String value="";
                try {
                    name = URLDecoder.decode(name, "UTF-8");
                } catch (Exception e) {
                }
               
                List<String> valueList = qp.get(name);
                if (valueList == null) {
                    valueList = new LinkedList<String>();
                    qp.put(name, valueList);
                }

                valueList.add(value);
                
            }
        }

        RequestContext.getCurrentContext().setRequestQueryParams(qp);
        return qp;
    }
           

繼續閱讀