繁体   English   中英

如何在 Spring Cloud Gateway 中编辑 multipart/form-data 请求数据?

[英]How can I edit multipart/form-data request data in Spring Cloud Gateway?

我正在使用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;
    }

或者

那么对于多部分请求修改,尤其是具有表单数据的请求修改,这个过程有点棘手。 不幸的是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());
                    }));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM