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