1. 程式人生 > >springcloud 中 zuul 如何修改請求引數

springcloud 中 zuul 如何修改請求引數

一. 為什麼要用到這個

在基於 springcloud 構建的微服務系統中,通常使用閘道器zuul來進行一些使用者驗證等過濾的操作,比如 使用者在 header 或者 url 引數中存放了 token ,閘道器層需要 用該 token 查出使用者 的 userId ,並存放於 request 中,以便後續微服務可以直接使用而避免再去用 token 查詢。

二.基礎知識

在 zuul 中最大的用法的除了路由之外,就是過濾器了,自定義過濾器需實現介面 ZuulFilter ,在 run() 方法中,可以用

  1. RequestContext ctx = RequestContext.getCurrentContext();
  2. HttpServletRequest request = ctx.getRequest();

獲取到 request,但是在 request 中只有 getParameter() 而沒有 setParameter() 方法,所以直接修改 url 引數不可行,另外在 reqeust 中可以雖然可以使用 setAttribute() ,但是可能由於作用域的不同,在這裡設定的 attribute 在後續的微服務中是獲取不到的,因此必須考慮另外的方式。

三.具體做法

最後確定的可行的方法是,用

ctx.setRequest(new HttpServletRequestWrapper(request) {})

的方式,重新構造上下文中的 request ,程式碼如下:

  1. import javax.servlet.http.HttpServletRequestWrapper;
  2. // 在json引數中新增 userId
  3. try {
  4. InputStream in = ctx.getRequest().getInputStream();
  5. String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
  6. System.out.println("body:" + body);
  7. JSONObject json = JSONObject.fromObject(body);
  8. json.put("userId", userId);
  9.   String newBody = json.toString();
  10. System.out.println("newBody:" + newBody);
  11. final byte[] reqBodyBytes = newBody.getBytes();
  12. ctx.setRequest(new HttpServletRequestWrapper(request){
  13. @Override
  14.   public ServletInputStream getInputStream() throws IOException {
  15. return new ServletInputStreamWrapper(reqBodyBytes);
  16. }
  17. @Override
  18. public int getContentLength() {
  19. return reqBodyBytes.length;
  20. }
  21. @Override
  22. public long getContentLengthLong() {
  23. return reqBodyBytes.length;
  24. }
  25. });
  26. } catch (IOException e) {
  27. e.printStackTrace();
  28. }

思路就是,獲取請求的輸入流,並重寫,即重寫json引數。

在後續的微服務的 controller 中,可以用 形似

  1. @RequestBody Map<String,Object> body
  2. =======
  3. body.get("userId");

這樣的方式,去獲取在 zuulFilter 傳入的 userId

四.一些嘗試

在重寫  HttpServletRequestWrapper 的時候,我嘗試過 重寫 getParameterNames() 和 getParameterMap() 方法,希望重寫 url 引數,但是並沒有生效。具體原因不太清楚,如果有大神知道怎麼辦,歡迎指教。

=================================

以上嘗試 已經找到可行方法:

  1. request.getParameterMap();// 關鍵步驟,一定要get一下,下面這行程式碼才能取到值
  2. Map<String, List<String>> requestQueryParams = ctx.getRequestQueryParams();
  3. if (requestQueryParams == null) {
  4. requestQueryParams = new HashMap<>();
  5. }
  6. // 新增userId
  7. ArrayList<String> arrayList2 = new ArrayList<>();
  8. arrayList.add(userId + "");
  9. requestQueryParams.put("userId", arrayList2);
  10. ctx.setRequestQueryParams(requestQueryParams);