【问题标题】:How can I edit multipart/form-data request data in Spring Cloud Gateway?如何在 Spring Cloud Gateway 中编辑 multipart/form-data 请求数据?
【发布时间】:2019-11-12 19:34:04
【问题描述】:

我使用spring cloud gateway做参数检查,如何编辑multipart/form-data请求数据?

我可以读取参数,但我不知道如何编辑它。

我认为问题的关键在于不知道如何对请求参数进行序列化和反序列化。

if (MediaType.MULTIPART_FORM_DATA.isCompatibleWith(mediaType)) {
            exchange.getRequest().getBody().collectList().flatMap(dataBuffers -> {
                final byte[] totalBytes = dataBuffers.stream().map(dataBuffer -> {
                    try {
                        final byte[] bytes = IOUtils.toByteArray(dataBuffer.asInputStream());
                        return bytes;
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }).reduce(this::addBytes).get();
                final ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
                    @Override
                    public Flux<DataBuffer> getBody() {
                        return Flux.just(buffer(totalBytes));
                    }
                };
                final ServerCodecConfigurer configurer = ServerCodecConfigurer.create();
                final Mono<MultiValueMap<String, Part>> multiValueMapMono = repackageMultipartData(decorator, configurer);

                return multiValueMapMono.flatMap(part -> {
                    for (String key : part.keySet()) {
                       // read parameters

                    }
                    return chain.filter(exchange.mutate().request(decorator).build());
                });

            });

        }


     private DataBuffer buffer(byte[] bytes) {
        final NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
        final DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
        buffer.write(bytes);
        return buffer;
    }

    @SuppressWarnings("unchecked")
    private static Mono<MultiValueMap<String, Part>> repackageMultipartData(ServerHttpRequest request, ServerCodecConfigurer configurer) {
        try {
            final MediaType contentType = request.getHeaders().getContentType();
            if (MediaType.MULTIPART_FORM_DATA.isCompatibleWith(contentType)) {
                return ((HttpMessageReader<MultiValueMap<String, Part>>) configurer
                        .getReaders()
                        .stream()
                        .filter(reader -> reader.canRead(MULTIPART_DATA_TYPE, MediaType.MULTIPART_FORM_DATA))
                        .findFirst()
                        .orElseThrow(() -> new IllegalStateException("No multipart HttpMessageReader.")))
                        .readMono(MULTIPART_DATA_TYPE, request, Collections.emptyMap())
                        .switchIfEmpty(EMPTY_MULTIPART_DATA)
                        .cache();
            }
        } catch (InvalidMediaTypeException ex) {
            // Ignore
        }
        return EMPTY_MULTIPART_DATA;
    }

    public byte[] addBytes(byte[] first, byte[] second) {
        final byte[] result = Arrays.copyOf(first, first.length + second.length);
        System.arraycopy(second, 0, result, first.length, second.length);
        return result;
    }

【问题讨论】:

  • 只是一个问题,使用Mono&lt;MultiValueMap&lt;String, Part&gt;&gt; multivalueMap = exchange.getMultipartData()的方法提取零件不是更简单吗?
  • 感谢您的评论,我会尝试这种方式。
  • 如何编辑交易所的MultipartData?

标签: java spring-cloud multipartform-data spring-webflux gateway


【解决方案1】:

对于多部分请求修改,尤其是具有表单数据的请求,这个过程有点棘手。不幸的是,ModifyRequestBodyGatewayFilterFactory 不会直接提供帮助,因为无法转换字符串->多部分->字符串。

这里的过程是读取整个请求,将其转换为多部分,对其进行修改,然后将其作为字符串设置回修改后的请求。目前没有工厂方法可以进行这种转换,但是您仍然可以使用该方法并执行以下操作:

             ServerRequest serverRequest = ServerRequest.create(exchange, messageReaders);
            
            // get modified body from original body o
            Mono<MultiValueMap<String, String>> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(o -> {
                // create mock request to read body
                SynchronossPartHttpMessageReader synchronossReader = new SynchronossPartHttpMessageReader();
                MultipartHttpMessageReader reader = new MultipartHttpMessageReader(synchronossReader);
                MockServerHttpRequest request = MockServerHttpRequest.post("").contentType(exchange.getRequest().getHeaders().getContentType()).body(o);
                Mono<MultiValueMap<String, Part>> monoRequestParts = reader.readMono(MULTIPART_DATA_TYPE, request, Collections.emptyMap());
                // modify parts
                return monoRequestParts.flatMap(requestParts -> {
                    Map<String, List<String>> modifedBodyArray = requestParts.entrySet().stream().map(entry -> {
                        String key = entry.getKey();
                        LOGGER.info(key);
                        List<String> entries = entry.getValue().stream().map(part -> {
                            LOGGER.info("{}", part);
                            // read the input part
                            String input = ((FormFieldPart) part).value();
                            // return the modified input part
                            return new String(modifyRequest(config, exchange, key, input));
                        }).collect(Collectors.toList());
                        return new Map.Entry<String, List<String>>() {
                            @Override
                            public String getKey() {
                                return key;
                            }
                            @Override
                            public List<String> getValue() {
                                return entries;
                            }
                            @Override
                            public List<String> setValue(List<String> param1) {
                                return param1;
                            }
                        };
                    }).collect(Collectors.toMap(k -> k.getKey(), k -> k.getValue()));
                    return Mono.just(new LinkedMultiValueMap<String, String>(modifedBodyArray));
                });
            });
            
            // insert the new modified body
            BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, new ParameterizedTypeReference<MultiValueMap<String, String>>() {});
            HttpHeaders headers = new HttpHeaders();
            headers.putAll(exchange.getRequest().getHeaders());

            // the new content type will be computed by bodyInserter
            // and then set in the request decorator
            headers.remove(HttpHeaders.CONTENT_LENGTH);
            
            CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
            return bodyInserter.insert(outputMessage, new BodyInserterContext())
                    .then(Mono.defer(() -> {
                        ServerHttpRequest decorator = decorate(exchange, headers, outputMessage);
                        return chain.filter(exchange.mutate().request(decorator).build());
                    }));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多