请求代理转发(四)

请求代理转发(四)

使用 webclient 代理请求和支持文件上传

代理 Api

@Slf4j
@RestController
public class ProxyApi {


    private WebClient.Builder builder = WebClient.builder();

    public WebClient client() {
        return Webclient.create();
    }

    private static final String CLIENT_RESPONSE_ATTR = "CLIENT_RESPONSE_ATTR";

    private static final String PERCENTAGE_SIGN = "%";

    //目标服务器
    @Value("${hq.host:http://localhost:7777}")
    private String host;

    private static final String prefix = "/proxy";

    @RequestMapping(prefix + "/**")
    public Mono<Void> proxy(ServerWebExchange exchange) {
            URI requestUrl = rebuildURI(exchange);
            log.info(">>>>> proxy url: {}", requestUrl);
            ServerHttpRequest request = exchange.getRequest();
            HttpMethod method = request.getMethod();
            WebClient.RequestBodySpec bodySpec = client().method(method).uri(requestUrl).headers(httpHeaders -> {
                httpHeaders.addAll(exchange.getRequest().getHeaders());
                httpHeaders.remove("Host");
            });
            if (isUploadRequest(request)) {
                //处理上传
                return exchange.getMultipartData().flatMap(mmp -> {
                    WebClient.RequestHeadersSpec<?> headersSpec = bodySpec.body(BodyInserters.fromMultipartData(mmp));
                    return doProxy(exchange, headersSpec);
                });
            }
            WebClient.RequestHeadersSpec<?> headersSpec;
            if (requiresBody(method)) {
                headersSpec = bodySpec.body(BodyInserters.fromDataBuffers(request.getBody()));
            } else {
                headersSpec = bodySpec;
            }
            return doProxy(exchange, headersSpec);
        
    }

    private static boolean isUploadRequest(ServerHttpRequest request) {
        return request.getHeaders().getContentType() != null && request.getHeaders().getContentType().equalsTypeAndSubtype(MediaType.MULTIPART_FORM_DATA);
    }

    public Mono<? extends Void> doProxy(ServerWebExchange exchange, WebClient.RequestHeadersSpec<?> headersSpec) {
        return headersSpec.exchange().log().flatMap(clientResponse -> {
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(clientResponse.statusCode());
            response.getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);
            exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, clientResponse);
            return Mono.justOrEmpty(1);
        }).flatMap(a -> {
            ClientResponse clientResponse = exchange.getAttribute(CLIENT_RESPONSE_ATTR);
            if (clientResponse == null) {
                return Mono.empty();
            }
            ServerHttpResponse response = exchange.getResponse();
            return clientResponse.bodyToMono(String.class).flatMap(str -> {
                try {
                    log.info(">>>>>>>> response {}", str);
                    //自定义返回json
                    DataBuffer wrap = response.bufferFactory().wrap(str.getBytes(StandardCharsets.UTF_8));
                    return response.writeWith(Mono.just(wrap));
                } catch (Exception e) {
                    return Mono.error(e);
                }
            });
        });
    }

    private URI rebuildURI(ServerWebExchange exchange) {
        URI original = exchange.getRequest().getURI();
        String path = path(prefix, exchange);
        URI uri = URI.create(host);
        //这个方式可以 copy get 请求的参数
        return UriComponentsBuilder.fromUri(original).scheme(uri.getScheme()).host(uri.getHost())
                .port(uri.getPort()).replacePath(path).build(containsEncodedParts(original)).toUri();
    }

    /**
     * @param prefix
     * @param exchange
     * @return
     */
    private String path(String prefix, ServerWebExchange exchange) {
        //获取 完整的请求 url
        String path = exchange.getRequest().getURI().getPath();
        return path.substring(prefix.length());
    }

    private boolean requiresBody(HttpMethod method) {
        switch (method) {
            case PUT:
            case POST:
            case PATCH:
                return true;
            default:
                return false;
        }
    }


    public static boolean containsEncodedParts(URI uri) {
        boolean encoded = (uri.getRawQuery() != null && uri.getRawQuery().contains(PERCENTAGE_SIGN))
                || (uri.getRawPath() != null && uri.getRawPath().contains(PERCENTAGE_SIGN));
        if (encoded) {
            try {
                UriComponentsBuilder.fromUri(uri).build(true);
                return true;
            } catch (IllegalArgumentException ignored) {
                if (log.isTraceEnabled()) {
                    log.trace("Error in containsEncodedParts", ignored);
                }
            }
            return false;
        }
        return encoded;
    }
}

服务api:

@PostMapping(value = "/body")
public Mono<R<String>> body(@RequestBody String name) {
    log.info("name: {}", name);
    return Mono.just(R.ok("success"));
}


@PostMapping(value = "/form")
public Mono<R<String>> form(String name) {
    log.info("name: {}", name);
    return Mono.just(R.ok("success"));
}

@RequestMapping(value = "/get")
public Mono<R<String>> get(String name) {
    log.info("name: {}", name);
    return Mono.just(R.ok("success"));
}


@PostMapping(value = "/upload")
public Mono<R<String>> index(@RequestPart("file") FilePart filePart,
		 ServerWebExchange exchange) throws IOException {
    System.out.println(filePart.filename());
    Path file = Files.createFile(Paths.get("test".concat(filePart.filename())));
    filePart.transferTo(file.toFile());
    return Mono.just(R.ok("success"));
}

good luck!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值