Spring跨系统转发HTTP请求的简易实现(支持下载文件二进制流) 背景 需求 使用RestTemplate转发所有请求

有一个系统是Web端,作为Gateway服务,背后有许多微服务,可以经过HTTP转发过去,同时这个Web系统作为权限认证,因此可以修改一些Header,放一些用户信息给到后端系统。

需求

就是将HttpServletRequest 翻译成一个RestTemplate请求

使用RestTemplate转发所有请求

public static ResponseEntity<byte[]> dispatchHttpRequest(HttpServletRequest request, String url,
                                                         Map<String, String[]> params, HttpHeaders headerParams,
                                                         String service, boolean isFile) {
        HttpHeaders requestHeaders = new HttpHeaders();
        HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());

        //复制原始HttpHeaders
        Enumeration<?> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = (String) headerNames.nextElement();
            String value = request.getHeader(key);
            requestHeaders.set(key, value);
        }
           
        requestHeaders.setAll(headerParams.toSingleValueMap());

        if (httpMethod.equals(HttpMethod.GET)) {
            requestHeaders.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
        }
        //读取RequestBody, 似乎读取不到 Form参数。
        String dataFromRequest = getJsonDataFromRequest(request);

        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url).query(request.getQueryString());
        UriComponents build;
        try {
            params.forEach(builder::queryParam);
            build = builder.build(true);
        }catch (Exception e) {
            throw new BaseException(-1, "参数不合法:" + e.getMessage());
        }
        Optional<List<String>> contentTypes = Optional.ofNullable(requestHeaders.get(HttpHeaders.CONTENT_TYPE));
        
        //修改Content-Type
        if (contentTypes.isPresent()
                && !contentTypes.get().contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8")
            && !contentTypes.get().contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
            && !contentTypes.get().contains(MediaType.APPLICATION_JSON_UTF8_VALUE)
            && !contentTypes.get().contains(MediaType.APPLICATION_JSON_VALUE)
        ) {
          requestHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
        }
        //设置默认值为JSON。
        if (!httpMethod.equals(HttpMethod.GET) && !contentTypes.isPresent()) {
          requestHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8);
        }

        logger.info("data from request: {}", dataFromRequest);
        HttpEntity<?> entity  = new HttpEntity<>(dataFromRequest, requestHeaders);
        
        //处理 APPLICATION_FORM_URLENCODED形式编码 的参数
        if (!httpMethod.equals(HttpMethod.GET)
            && contentTypes.isPresent() && (
                    contentTypes.get().contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
                || contentTypes.get().contains(MediaType.APPLICATION_FORM_URLENCODED_VALUE + ";charset=UTF-8"))
            && requestHeaders.getContentLength() > 0
        ) {
            MultiValueMap<String, String> parameters = new LinkedMultiValueMap<>();
            Enumeration parameterNames = request.getParameterNames();
            while (parameterNames.hasMoreElements()) {
                String o = (String)parameterNames.nextElement();
                if (!build.getQueryParams().containsKey(o)) {
                    parameters.add(o, request.getParameter(o));
                }
            }
            logger.info("parameterMap {}", parameters);
            if (StringUtils.isBlank(dataFromRequest)) {
                entity = new HttpEntity<>(parameters,  requestHeaders);
            }
        }
        logger.info("Content-Type: {}, Content-Length: {}", requestHeaders.getContentType(), requestHeaders.getContentLength());
        logger.debug("after url: {} entity: {}", build.toUriString(), JSON.toJSONString(entity));
        ResponseEntity<byte[]> response;
        try {
            response = restTemplate.exchange(build.toUri(), httpMethod, entity, byte[].class);
        }catch (HttpClientErrorException httpClientException) {
            if (httpClientException.getStatusCode().value() == 404) {
                throw new BaseException(-1, service + "可能已经离线或重启中,请稍后再访问,因为您访问的地址出现404错误");
            }
            if (isFile && httpClientException.getStatusCode().value() >= 400) {
                return ResponseEntity.status(HttpStatus.NOT_FOUND).body(httpClientException.getResponseBodyAsByteArray());
            }
            throw httpClientException;
        }
        return response;
    }

    private static String getJsonDataFromRequest(HttpServletRequest request) {
        BufferedReader br = null;
        StringBuilder sb = new StringBuilder();
        try {
            br = new BufferedReader(new InputStreamReader(request.getInputStream(), "utf-8"));
            String temp;
            while ((temp = br.readLine()) != null) {
                sb.append(temp);
            }
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sb.toString();
    }