spring boot-接口代理服务转发实现

spring boot-接口代理服务实现

背景

业务中对接了第三方服务,有些接口需要进行透传转发,又不想直接经过公网网关,所有就要实现一个类似网关转发的接口

目标

  • 实现基本的接口转发,get, post请求 (比较容易)
  • 支持文件转发请求

转发原理

  • 接收客户端所有的请求参数,从request中获取请求参数,如headers, queryParameters,文件信息
  • 使用客户端工具,如httpclient 或者使用 restTemplate 客户端进行参数再次拼接转发请求
  • 我们使用 restTemplate ,如果要要求性能,可以使用连接池

实现

RouteProperties, RouteInfo 路由信息

@Data
@Configuration
@ConfigurationProperties(prefix = "proxy.svc")
public class RouteProperties {
    //map<服务,路由>
    private Map<String, RouteInfo> routes;

    /**
     * 获取路由
     *
     * @param prefix
     * @return
     */
    public RouteInfo getRouteByPrefix(String prefix) {
        return routes.entrySet().stream()
                .map(Map.Entry::getValue).filter(r -> r.getPrefix().equals(prefix))
                .findFirst().orElse(null);
    }
}

@Data
public class RouteInfo {
    /**
     * 路由前缀
     */
    private String prefix;
    /**
     * 主机 http://开头
     */
    private String host;
}
ProxyController
@Slf4j
@RestController
public class ProxyController {

    @Autowired
    private RouteProperties routeProperties;

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 请求转发
     * 支持 文件转发
     *
     * @param prefix
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/{prefix}/**")
    public ResponseEntity proxy(@PathVariable String prefix, HttpServletRequest request, HttpServletResponse response) {
        try {
            RouteInfo route = routeProperties.getRouteByPrefix(prefix);
            if (route == null) {
                return new ResponseEntity("No route found!", HttpStatus.INTERNAL_SERVER_ERROR);
            }
            String url = rebuildUlr(request, route.getHost(), prefix);
            log.info("proxy url: {}", url);
            RequestEntity requestEntity = buildRequestEntity(url, request);
            return restTemplate.exchange(requestEntity, String.class);
        } catch (Exception e) {
            return new ResponseEntity("server Error", HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }

    private RequestEntity buildRequestEntity(String url, HttpServletRequest request) throws IOException {
        //获取 所有heads
        HttpHeaders headers = parseHeader(request);
        //单独处理文件上传
        if (isMultipart(request)) {
            RequestEntity formData = getFormDataEntity(url, request, headers);
            if (formData != null) {
                return formData;
            }
            throw new RuntimeException("参数异常");
        }
        //这里获取不到 form-data 中数据,只能获取,requestBody, form-urlencoded-www参数
        byte[] body = parseBody(request);
        log.info("request: {}", new String(body));
        return new RequestEntity(body, headers, HttpMethod.resolve(request.getMethod()), URI.create(url));
    }


    private RequestEntity getFormDataEntity(String url, HttpServletRequest request, HttpHeaders headers) throws IOException {
        MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
        MultiValueMap<String, MultipartFile> multiFileMap = multipartHttpServletRequest.getMultiFileMap();
        //处理文件
        MultiValueMap formData = new LinkedMultiValueMap();
        for (Map.Entry<String, List<MultipartFile>> entry : multiFileMap.entrySet()) {
            String key = entry.getKey();
            for (MultipartFile multipartFile : entry.getValue()) {
                ByteArrayResource fileResource = new ByteArrayResource(multipartFile.getBytes()) {
                    @Override
                    public long contentLength() {
                        return multipartFile.getSize();
                    }

                    @Override
                    public String getFilename() {
                        return multipartFile.getOriginalFilename();
                    }
                };
                formData.add(key, fileResource);
            }
        }
        //处理 form-data 中非 文件类型参数
        Map<String, String[]> parameterMap = multipartHttpServletRequest.getParameterMap();
        for (Map.Entry<String, String[]> stringEntry : parameterMap.entrySet()) {
            for (String s : stringEntry.getValue()) {
                formData.add(stringEntry.getKey(), s);
            }
        }
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        return new RequestEntity(formData, headers, HttpMethod.resolve(request.getMethod()), URI.create(url));
    }

    private boolean isMultipart(HttpServletRequest request) {
        return request instanceof MultipartHttpServletRequest;
    }

    private HttpHeaders parseHeader(HttpServletRequest request) {
        HttpHeaders headers = new HttpHeaders();
        Iterator<String> iterator = request.getHeaderNames().asIterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            List<String> list = Collections.list(request.getHeaders(next));
            for (String s : list) {
                headers.add(next, s);
            }
        }
        return headers;
    }

    private byte[] parseBody(HttpServletRequest request) throws IOException {
        return StreamUtils.copyToByteArray(request.getInputStream());
    }

    private String rebuildUlr(HttpServletRequest request, String host, String prefix) {
        String query = request.getQueryString();
        return host.concat(request.getRequestURI().replace(prefix, "")).concat(query != null ? "?".concat(query) : "");
    }
}

application.properties 配置文件

# 设置文件上传大小
spring.servlet.multipart.max-file-size=2GB
spring.servlet.multipart.max-request-size=2GB
# user 服务 的 前缀
proxy.svc.routes.user.prefix=usr
# user 服务的目标地址
proxy.svc.routes.user.host=http://localhost:9090

访问

http://localhost:8080/usr/user/1:

{
    "data": {
        "id": 1,
        "name": "test",
        "age": 12
    },
    "code": "1",
    "message": null
}

good luck!

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Spring Boot提供了对WebSocket的支持,可以通过反向代理来实现WebSocket的连接。 反向代理是一种服务器架构模式,它将客户端的请求转发到后端服务器,并将后端服务器的响应返回给客户端。在WebSocket中,反向代理可以用于将客户端的WebSocket请求转发到后端的WebSocket服务器。 要实现Spring Boot反向代理WebSocket,可以按照以下步骤进行操作: 1. 配置反向代理服务器:在反向代理服务器上配置WebSocket代理规则,将客户端的WebSocket请求转发到后端的WebSocket服务器。常见的反向代理服务器有Nginx和Apache等。 2. 配置Spring Boot应用:在Spring Boot应用中,需要添加WebSocket的依赖,并配置WebSocket相关的类和路由。 - 添加依赖:在`pom.xml`文件中添加`spring-boot-starter-websocket`依赖。 - 配置WebSocket类:创建一个继承自`WebSocketConfigurer`接口的类,并实现其中的方法。在`registerWebSocketHandlers`方法中,配置WebSocket处理器和路由。 - 配置WebSocket路由:在`registerWebSocketHandlers`方法中,使用`registry.addHandler()`方法配置WebSocket处理器和路由。可以指定处理器和路由的路径。 3. 配置反向代理规则:在反向代理服务器上配置WebSocket的反向代理规则,将客户端的WebSocket请求转发Spring Boot应用的WebSocket处理器和路由。 以上是实现Spring Boot反向代理WebSocket的基本步骤。具体的配置和实现方式可以根据具体的需求和环境进行调整。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值