001package top.cenze.utils.http.request;
002
003import cn.hutool.core.collection.CollectionUtil;
004import cn.hutool.core.convert.Convert;
005import cn.hutool.core.util.StrUtil;
006import com.alibaba.fastjson.JSON;
007import com.alibaba.fastjson.JSONObject;
008import com.google.common.collect.Maps;
009import com.netflix.zuul.context.RequestContext;
010import com.netflix.zuul.http.ServletInputStreamWrapper;
011import lombok.SneakyThrows;
012import lombok.extern.slf4j.Slf4j;
013import org.apache.commons.lang3.StringUtils;
014import org.springframework.http.MediaType;
015import org.springframework.util.StreamUtils;
016import org.springframework.web.multipart.MultipartHttpServletRequest;
017import org.springframework.web.multipart.MultipartResolver;
018import org.springframework.web.multipart.commons.CommonsMultipartResolver;
019
020import javax.servlet.ServletInputStream;
021import javax.servlet.http.HttpServletRequest;
022import javax.servlet.http.HttpServletRequestWrapper;
023import java.io.IOException;
024import java.io.InputStream;
025import java.net.InetAddress;
026import java.net.UnknownHostException;
027import java.nio.charset.Charset;
028import java.util.Arrays;
029import java.util.HashMap;
030import java.util.List;
031import java.util.Map;
032
033@Slf4j
034public class ZuulUtil {
035
036    // 多次反向代理后会有多个ip值 的分割符
037    private final static String IP_UTILS_FLAG = ",";
038    // 未知IP
039    private final static String UNKNOWN = "unknown";
040    // 本地 IP
041    private final static String LOCALHOST_IP = "0:0:0:0:0:0:0:1";
042    private final static String LOCALHOST_IP1 = "127.0.0.1";
043
044    /**
045     * 获取请求TOKEN
046     * @param ctx
047     * @return
048     */
049    public static String getToken(RequestContext ctx) {
050        // 请求
051        HttpServletRequest request = ctx.getRequest();
052
053        String token = request.getHeader("TOKEN");
054        if (StringUtils.isBlank(token)) {
055            token = getParameter(ctx, "TOKEN");
056        }
057
058        return token;
059    }
060
061    /**
062     * 获取请求参数
063     * @param ctx
064     * @param name
065     * @return
066     */
067    @SneakyThrows
068    public static String getParameter(RequestContext ctx, String name) {
069        // 请求
070        HttpServletRequest request = ctx.getRequest();
071        // 请求方法
072        String method = request.getMethod();
073        // 获取Content-Type头部
074        String contentType = request.getHeader("Content-Type");
075
076        // get方法,和post、put方法处理方式不同
077        if ("GET".equals(method)) {
078            // 一定要在获取参数前设置一下编码,防止获取的中文乱码
079            request.setCharacterEncoding("UTF-8");
080            // 关键步骤,一定要get一下,下面才能取到值requestQueryParams
081            request.getParameterMap();
082            Map<String, List<String>> requestQueryParams = ctx.getRequestQueryParams();
083            if (requestQueryParams == null) {
084                requestQueryParams = new HashMap<>();
085            }
086            log.info("getParameter requestQueryParams: {}", JSON.toJSONString(requestQueryParams));
087
088            // 获取参数的第一个值
089            List<String> lstParam = requestQueryParams.get(name);
090            if (CollectionUtil.isNotEmpty(lstParam)) {
091                return lstParam.get(0);
092            }
093        }
094        // post和put需重写HttpServletRequestWrapper
095        else if ("POST".equals(method) || "PUT".equals(method)) {
096            if (!MediaType.MULTIPART_FORM_DATA_VALUE.equals(contentType)) {
097                // 获取请求的输入流
098                InputStream in = request.getInputStream();
099                String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
100                // 如果body为空初始化为空json
101                if (StrUtil.isEmpty(body)) {
102                    body = "{}";
103                }
104                log.info("getParameter body: {}", body);
105                try {
106                    // 转化成map
107                    Map<String, Object> params = JSONObject.parseObject(body);
108                    if (CollectionUtil.isEmpty(params)) {
109                        params = Maps.newHashMap();
110                    }
111                    return Convert.toStr(params.get(name));
112                } catch (Exception e) {
113                    log.error("getParameter err: {}", e.getMessage());
114                }
115            } else {
116                MultipartResolver resolver = new CommonsMultipartResolver(request.getSession().getServletContext());
117                MultipartHttpServletRequest multipartRequest = resolver.resolveMultipart(request);
118                return multipartRequest.getParameter(name);
119            }
120        }
121
122        return null;
123    }
124
125    /**
126     * 添加修改请求参数
127     * @param ctx
128     * @param name
129     * @param value
130     */
131    @SneakyThrows
132    public static void setParameter(RequestContext ctx, String name, Object value) {
133        Map<String, Object> mapParams = new HashMap<>();
134        mapParams.put(name, value);
135
136        setParameters(ctx, mapParams);
137    }
138
139    /**
140     * 添加修改请求参数集合
141     * @param ctx
142     * @param mapParams
143     */
144    @SneakyThrows
145    public static void setParameters(RequestContext ctx, Map<String, Object> mapParams) {
146        // 请求
147        HttpServletRequest request = ctx.getRequest();
148        // 请求方法
149        String method = request.getMethod();
150
151        // get方法,和post、put方法处理方式不同
152        if ("GET".equals(method)) {
153            // 一定要在获取参数前设置一下编码,防止获取的中文乱码
154            request.setCharacterEncoding("UTF-8");
155            // 关键步骤,一定要get一下,下面才能取到值requestQueryParams
156            request.getParameterMap();
157            Map<String, List<String>> requestQueryParams = ctx.getRequestQueryParams();
158            if (requestQueryParams == null) {
159                requestQueryParams = new HashMap<>();
160            }
161            log.info("setParameter requestQueryParams: {}", JSON.toJSONString(requestQueryParams));
162
163            // 添加/修改参数
164            if (CollectionUtil.isNotEmpty(mapParams)) {
165                for (Map.Entry<String, Object> entry : mapParams.entrySet()) {
166                    requestQueryParams.put(entry.getKey(), Arrays.asList(Convert.toStr(entry.getValue())));
167                }
168
169                log.info("setParameter newQueryParams: {}", JSON.toJSONString(requestQueryParams));
170                ctx.setRequestQueryParams(requestQueryParams);
171            }
172        }
173        // post和put需重写HttpServletRequestWrapper
174        else if ("POST".equals(method) || "PUT".equals(method)) {
175            // 获取请求的输入流
176            InputStream in = request.getInputStream();
177            String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
178            log.info("setParameter body: {}", body);
179            // 如果body为空初始化为空json
180            if (StrUtil.isEmpty(body)) {
181                body = "{}";
182            }
183            log.info("setParameter body: {}", body);
184            try {
185                // 转化成map
186                Map<String, Object> params = JSONObject.parseObject(body);
187                if (CollectionUtil.isEmpty(params)) {
188                    params = Maps.newHashMap();
189                }
190
191                // 添加/修改参数
192                if (CollectionUtil.isNotEmpty(mapParams)) {
193                    for (Map.Entry<String, Object> entry : mapParams.entrySet()) {
194                        params.put(entry.getKey(), entry.getValue());
195                    }
196
197                    String newBody = params.toString();
198                    log.info("setParameter newBody: {}", newBody);
199                    final byte[] reqBodyBytes = newBody.getBytes();
200
201                    // 重写上下文的HttpServletRequestWrapper
202                    ctx.setRequest(new HttpServletRequestWrapper(request) {
203                        @Override
204                        public ServletInputStream getInputStream() throws IOException {
205                            return new ServletInputStreamWrapper(reqBodyBytes);
206                        }
207
208                        @Override
209                        public int getContentLength() {
210                            return reqBodyBytes.length;
211                        }
212
213                        @Override
214                        public long getContentLengthLong() {
215                            return reqBodyBytes.length;
216                        }
217                    });
218                }
219            } catch (Exception e) {
220                log.error("setParameter err: {}", e.getMessage());
221            }
222        }
223    }
224
225    /**
226     * 获取访问者真实ip
227     * @param ctx
228     * @return
229     */
230    public static String getRemoteIP(RequestContext ctx) {
231        // 获取请求
232        HttpServletRequest request = ctx.getRequest();
233
234        return getRemoteIP(request);
235    }
236
237    /**
238     * 获取访问者真实ip
239     * @param request
240     * @return
241     */
242    public static String getRemoteIP(HttpServletRequest request) {
243        String ip = null;
244        try {
245            // 以下两个获取在k8s中,将真实的客户端IP,放到了x-Original-Forwarded-For。而将WAF的回源地址放到了 x-Forwarded-For了。
246            ip = request.getHeader("X-Original-Forwarded-For");
247            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
248                ip = request.getHeader("X-Forwarded-For");
249            }
250            // 获取nginx等代理的ip
251            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
252                ip = request.getHeader("x-forwarded-for");
253            }
254            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
255                ip = request.getHeader("Proxy-Client-IP");
256            }
257            if (StrUtil.isEmpty(ip) || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
258                ip = request.getHeader("WL-Proxy-Client-IP");
259            }
260            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
261                ip = request.getHeader("HTTP_CLIENT_IP");
262            }
263            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
264                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
265            }
266            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
267                ip = request.getHeader("X-Real-IP");
268            }
269            // 兼容k8s集群获取ip
270            if (StrUtil.isEmpty(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
271                ip = request.getRemoteAddr();
272                if (LOCALHOST_IP1.equalsIgnoreCase(ip) || LOCALHOST_IP.equalsIgnoreCase(ip)) {
273                    // 根据网卡取本机配置的IP
274                    InetAddress iNet = null;
275                    try {
276                        iNet = InetAddress.getLocalHost();
277                    } catch (UnknownHostException e) {
278                        log.error("getClientIp error: ", e);
279                    }
280                    ip = iNet.getHostAddress();
281                }
282            }
283        } catch (Exception e) {
284            log.error("IPUtils ERROR ", e);
285        }
286
287        // 使用代理,则获取第一个IP地址
288        if (StrUtil.isNotEmpty(ip) && ip.indexOf(IP_UTILS_FLAG) > 0) {
289            ip = ip.substring(0, ip.indexOf(IP_UTILS_FLAG));
290        }
291
292        return ip;
293    }
294
295    /**
296     * 获取访问域名
297     * @param ctx
298     * @return
299     */
300    public static String getServerName(RequestContext ctx) {
301        // 获取请求
302        HttpServletRequest request = ctx.getRequest();
303
304        return getServerName(request);
305    }
306
307    /**
308     * 获取访问域名
309     * @param request
310     * @return
311     */
312    public static String getServerName(HttpServletRequest request) {
313        return request.getServerName();
314    }
315}