Spring-Cloud-Gateway修改请求(json,form带文件请求)参数,返回值参数

这篇具有很好参考价值的文章主要介绍了Spring-Cloud-Gateway修改请求(json,form带文件请求)参数,返回值参数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

新项目需要在getway统一做入参、出参加解密,记录日志。记录一下form,x-www-form-urlencoded , json 这几种修改数据的方式。
gateway做拦截器是实现GlobalFilter接口,修改json方式网上有很多文章,后来又想研究研究能不能实现修改form-data参数,以及文件请求,后者文章不多大部分是怎么读数据的教学。现在发一下我的实现方式。
使用的gateway版本是2.2.1.RELEASE cloud版本Greenwich.SR2


   @Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)   {
	    Mono<Void> mono = chain.filter(exchange);
		ServerHttpRequest request = exchange.getRequest();
		MediaType contentType = request.getHeaders().getContentType();

	    if (Objects.nonNull(contentType) && Objects.nonNull(exchange.getRequest().getMethod())
			&& exchange.getRequest().getMethod().equals(HttpMethod.POST)) {
		    if (MediaType.APPLICATION_JSON.isCompatibleWith(contentType)) {
			    // json 请求体处理
			    mono = this.transferBody(exchange, chain);
		    }else if(MediaType.MULTIPART_FORM_DATA.isCompatibleWith(contentType)){
		    	// multipart/form-data处理
				mono = this.fileRequest(contentType,exchange,chain);
			}else if(MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)){
		    	// x-www-form-urlencoded 格式处理
				mono = this.xwFromBody(exchange,chain);
			}
	    }else{
			if(exchange.getRequest().getMethod().equals(HttpMethod.GET)){
				Map<String, String> queryParams = exchange.getRequest().getQueryParams().toSingleValueMap();
				log.info("queryParams:{}", queryParams);
			}
		}
	    return mono;
	}

修改json数据

/**
	 * 修改修改body参数
	 */
	private Mono<Void> transferBody(ServerWebExchange exchange, GatewayFilterChain chain) {
	ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
	Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(Mono::just);

	BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
	HttpHeaders headers = new HttpHeaders();
	headers.putAll(exchange.getRequest().getHeaders());
	headers.remove(HttpHeaders.CONTENT_LENGTH);
	MyCachedBodyOutputMessage outputMessage = new MyCachedBodyOutputMessage(exchange, headers);
	ServerHttpRequest.Builder requestBuilder = exchange.getRequest().mutate();
	requestBuilder.headers(k -> k.remove("Content-length"));

	Mono mono = bodyInserter.insert(outputMessage, new BodyInserterContext())
			.then(Mono.defer(() -> {
				//解决body内数据过长读取不完整的问题
				Flux<DataBuffer> body = outputMessage.getBody();
				DataBufferHolder holder = new DataBufferHolder();
				try{
					body.subscribe(dataBuffer -> {
						int len = dataBuffer.readableByteCount();
						holder.length = len;
						byte[] bytes = new byte[len];
						dataBuffer.read(bytes);
						DataBufferUtils.release(dataBuffer);
						String oldBody = new String(bytes, StandardCharsets.UTF_8);
						JsonNode jsonNode = objectMapper.readTree(in);
						//到这可以读取数据,做校验之类的
					    //JsonNode token = oldDataJSON.get("token");
						jsonNode .set("test","修改数据");
						DataBuffer data = outputMessage.bufferFactory().allocateBuffer();
						data.write(jsonNode.toString().getBytes(StandardCharsets.UTF_8));
						holder.length = data.readableByteCount();
						holder.dataBuffer=data;
					});

				}catch (Exception e){
					if(e.getCause() instanceof ServiceException){
						ServiceException e1 = (ServiceException) e.getCause();
						return handleFailedRequest(exchange, JSONObject.toJSONString(CommonResponse.error(e1.getCode(), e1.getMessage())));
					}
					return handleFailedRequest(exchange, JSONObject.toJSONString(CommonResponse.error(SYSTEM_ERROR.getCode(), SYSTEM_ERROR.getMessage())));
				}


				ServerHttpRequestDecorator decorator = newDecorator(exchange,holder.length, Flux.just(holder.dataBuffer));
				return chain.filter(exchange.mutate().request(decorator).build());

			}));

		return mono;
	}

修改form表单参数,一般需要上传文件的请求用这个。数据读取都可以用json请求那个方法获取,但是带文件的请求用那个读了以后文件数据就变了,修改数据以后文件没法正常存储,所以按以下方式,直接读取字节然后拼接要改的数据

//修改form参数
	private Mono<Void> fileRequest(MediaType contentType,ServerWebExchange exchange, GatewayFilterChain chain){
		return DataBufferUtils.join(exchange.getRequest().getBody())
				.flatMap(dataBuffer -> {
					byte[] bytes = new byte[dataBuffer.readableByteCount()];
					dataBuffer.read(bytes);
					DataBufferUtils.release(dataBuffer);
					//  new String(bytes); 
					//添加一些自定义参数,或者校验
					String oldBody = addPara(contentType.toString(), new String(bytes));
					
					byte[] bytes1 = oldBody.getBytes();
					//这里截取数组是因为 form请求体数据末尾有--/r/n,这里需要截一段然后拼接自定义的数据。数据格式可以看文章末尾的链接
					byte[] bytes2 = byteMerger(Arrays.copyOf(bytes,bytes.length-4), bytes1);
					Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
						DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes2);
						DataBufferUtils.retain(buffer);
						return Mono.just(buffer);
					});
					ServerHttpRequestDecorator mutatedRequest = newDecorator(exchange,bytes2.length,cachedFlux);
					ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build();
					return ServerRequest.create(mutatedExchange, MESSAGE_READERS)
							.bodyToMono(byte[].class)
							.then(chain.filter(mutatedExchange));
				});
	}
	/**
	 * 修改form参数
	 * @param contentType 请求类型
	 * @param bodyString  请求body信息
	 */
	@SneakyThrows
	public static String addPara(String contentType, String bodyString) {
		StringBuffer stringBuffer = new StringBuffer();

		String boundary = contentType.substring(contentType.lastIndexOf("boundary=") + 9);//获取随机字符传信息
		String boundary_end = StrUtil.format("--{}--\r\n", boundary);
		Map<String, Object> formMap = Maps.newHashMap();
		/**
		 *
		 * 根据自己需求进行对bodyString信息修改,例如下面,根据boundary对传入的bodyString进行了分割
		 *  String[] split = bodyString.split(boundary);
		 *  然后将修改完后的信息封装到formMap中,需要注意的是,file文件需要以new FileResource(file, fileName)的形式当作value放到formMap中
		 */
		String part = "^\r\nContent-Disposition: form-data; name=\"([^/?]+)\"\r\n\r\n([^/?]+)\r\n--?$";
		Pattern r = Pattern.compile(part);
		String[] split = bodyString.split(boundary);
		for(int x=1;x<split.length-1;x++){
			Matcher m = r.matcher(split[x]);
			if(m.find()){
				String name = m.group(1);
				String value = m.group(2);
				System.out.println("name:"+name+" value:"+value);
//				formMap.put(name,value);
			}
		}

		formMap.put("test","添加自定义参数");
		formMap.put("tcu",22222);
		Integer count =0;
		for (Map.Entry<String, Object> entry : formMap.entrySet()) {
			stringBuffer.append(appendPart(boundary, entry.getKey(), entry.getValue(),count));
			count++;
		}
		stringBuffer.append(boundary_end);//拼接结束信息
		log.info(stringBuffer.toString());

		return stringBuffer.toString();
	}

修改x-www-form-urlencoded参数

	/**
	 * 修改 x-www-form-urlencoded参数
	 * @param exchange
	 * @param chain
	 * @return
	 */
	private Mono<Void> xwFromBody(ServerWebExchange exchange, GatewayFilterChain chain){
		ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
		Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(Mono::just);
		BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
		HttpHeaders headers = new HttpHeaders();
		headers.putAll(exchange.getRequest().getHeaders());
		headers.remove(HttpHeaders.CONTENT_LENGTH);
		MyCachedBodyOutputMessage outputMessage = new MyCachedBodyOutputMessage(exchange, headers);
		ServerHttpRequest.Builder requestBuilder = exchange.getRequest().mutate();
		requestBuilder.headers(k -> k.remove("Content-length"));

		return bodyInserter.insert(outputMessage, new BodyInserterContext())
				.then(Mono.defer(() -> {
					Flux<DataBuffer> body = outputMessage.getBody();
					DataBufferHolder holder = new DataBufferHolder();
					changeParamByXwForm(body,holder,outputMessage);
					ServerHttpRequestDecorator decorator = newDecorator(exchange,holder.length, Flux.just(holder.dataBuffer));
					return chain.filter(exchange.mutate().request(decorator).build());
				}));
	}
	//修改 x-www-form-urlencoded参数
	private void changeParamByXwForm(Flux<DataBuffer> body,DataBufferHolder holder,MyCachedBodyOutputMessage outputMessage){
		body.subscribe(dataBuffer -> {
			int len = dataBuffer.readableByteCount();
			holder.length = len;
			byte[] bytes = new byte[len];
			dataBuffer.read(bytes);
			DataBufferUtils.release(dataBuffer);
			String oldBody = new String(bytes, StandardCharsets.UTF_8);
			//直接拼接要改的数据就行
			oldBody+="&tcu=123888";
			DataBuffer data = outputMessage.bufferFactory().allocateBuffer();
			data.write(oldBody.getBytes(StandardCharsets.UTF_8));
			holder.length = data.readableByteCount();
			holder.dataBuffer=data;
		});
	}

修改请求参数完整代码 ReadAndChangeResFilter .java

import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.resource.MultiResource;
import cn.hutool.core.io.resource.Resource;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.Maps;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;

import org.springframework.cloud.gateway.support.BodyInserterContext;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.*;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerStrategies;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.core.Ordered;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.byaero.utm.common.constant.CommonErrorCodeEnum.SYSTEM_ERROR;
import static com.byaero.utm.common.constant.CommonErrorCodeEnum.TOKEN_NOT_EXISTENT_ERROR;

@Slf4j
@Component
public class ReadAndChangeResFilter implements GlobalFilter, Ordered {

	private static final String CONTENT_DISPOSITION_TEMPLATE = "Content-Disposition: form-data; name=\"{}\"\r\n\r\n";
	private static final String CONTENT_DISPOSITION_FILE_TEMPLATE = "Content-Disposition: form-data; name=\"{}\"; filename=\"{}\"\r\n";

	private static final String CONTENT_TYPE_MULTIPART_PREFIX = ContentType.MULTIPART.getValue() + "; boundary=";
	private static final String CONTENT_TYPE_FILE_TEMPLATE = "Content-Type: {}\r\n\r\n";

	private final static String TOKEN_USERINFO_CACHE_FLAG = "TI-%s";
	private static final List<HttpMessageReader<?>> MESSAGE_READERS = HandlerStrategies.withDefaults().messageReaders();

	@Autowired
	private RedisUtil redisUtil;
	@Autowired
	private UserConvert userConvert;
	@Autowired
	private ObjectMapper objectMapper;
	@Autowired
	private UserManager userManager;


    @Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)   {
	    Mono<Void> mono = chain.filter(exchange);
		ServerHttpRequest request = exchange.getRequest();
		MediaType contentType = request.getHeaders().getContentType();

		final GatewayContext gatewayContext = new GatewayContext();

//		ServerWebExchangeUtils.putUriTemplateVariables();
	    if (Objects.nonNull(contentType) && Objects.nonNull(exchange.getRequest().getMethod())
			&& exchange.getRequest().getMethod().equals(HttpMethod.POST)) {
		    if (MediaType.APPLICATION_JSON.isCompatibleWith(contentType)) {
			    // json 请求体处理
			    mono = this.transferBody(exchange, chain);
		    }else if(MediaType.MULTIPART_FORM_DATA.isCompatibleWith(contentType)){
		    	// multipart/form-data处理
				mono = this.fileRequest(contentType,exchange,chain);
			}else if(MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)){
		    	// x-www-form-urlencoded 格式处理
				mono = this.xwFromBody(exchange,chain);
			}
	    }else{
			if(exchange.getRequest().getMethod().equals(HttpMethod.GET)){
				Map<String, String> queryParams = exchange.getRequest().getQueryParams().toSingleValueMap();
				log.info("queryParams:{}", queryParams);
			}
		}
	    return mono;
	}
	//修改form参数
	private Mono<Void> fileRequest(MediaType contentType,ServerWebExchange exchange, GatewayFilterChain chain){
		return DataBufferUtils.join(exchange.getRequest().getBody())
				.flatMap(dataBuffer -> {
					byte[] bytes = new byte[dataBuffer.readableByteCount()];
					dataBuffer.read(bytes);
					DataBufferUtils.release(dataBuffer);
					String oldBody = addPara(contentType.toString(), new String(bytes));

					byte[] bytes1 = oldBody.getBytes();
					byte[] bytes2 = byteMerger(Arrays.copyOf(bytes,bytes.length-4), bytes1);
					Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
						DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes2);
						DataBufferUtils.retain(buffer);
						return Mono.just(buffer);
					});
					ServerHttpRequestDecorator mutatedRequest = newDecorator(exchange,bytes2.length,cachedFlux);
					ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build();
					return ServerRequest.create(mutatedExchange, MESSAGE_READERS)
							.bodyToMono(byte[].class)
							.then(chain.filter(mutatedExchange));
				});
	}
	public static byte[] byteMerger(byte[] bt1, byte[] bt2){
		byte[] bt3 = new byte[bt1.length+bt2.length];
		System.arraycopy(bt1, 0, bt3, 0, bt1.length);
		System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
		return bt3;
	}

	//修改 x-www-form-urlencoded参数
	private void changeParamByXwForm(Flux<DataBuffer> body,DataBufferHolder holder,MyCachedBodyOutputMessage outputMessage){
		body.subscribe(dataBuffer -> {
			int len = dataBuffer.readableByteCount();
			holder.length = len;
			byte[] bytes = new byte[len];
			dataBuffer.read(bytes);
			DataBufferUtils.release(dataBuffer);
			String oldBody = new String(bytes, StandardCharsets.UTF_8);
			oldBody+="&test=修改数据";
			DataBuffer data = outputMessage.bufferFactory().allocateBuffer();
			data.write(oldBody.getBytes(StandardCharsets.UTF_8));
			holder.length = data.readableByteCount();
			holder.dataBuffer=data;
		});
	}

	@Override
	public int getOrder() {
		return Ordered.HIGHEST_PRECEDENCE;
	}

	/**
	 * 修改 x-www-form-urlencoded参数
	 * @param exchange
	 * @param chain
	 * @return
	 */
	private Mono<Void> xwFromBody(ServerWebExchange exchange, GatewayFilterChain chain){
		ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
		Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(Mono::just);
		BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
		HttpHeaders headers = new HttpHeaders();
		headers.putAll(exchange.getRequest().getHeaders());
		headers.remove(HttpHeaders.CONTENT_LENGTH);
		MyCachedBodyOutputMessage outputMessage = new MyCachedBodyOutputMessage(exchange, headers);
		ServerHttpRequest.Builder requestBuilder = exchange.getRequest().mutate();
		requestBuilder.headers(k -> k.remove("Content-length"));

		return bodyInserter.insert(outputMessage, new BodyInserterContext())
				.then(Mono.defer(() -> {
					Flux<DataBuffer> body = outputMessage.getBody();
					DataBufferHolder holder = new DataBufferHolder();
					changeParamByXwForm(body,holder,outputMessage);
					ServerHttpRequestDecorator decorator = newDecorator(exchange,holder.length, Flux.just(holder.dataBuffer));
					return chain.filter(exchange.mutate().request(decorator).build());
				}));
	}

	/**
	 * 修改修改body参数
	 */
	private Mono<Void> transferBody(ServerWebExchange exchange, GatewayFilterChain chain) {
	ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
	Mono<String> modifiedBody = serverRequest.bodyToMono(String.class).flatMap(Mono::just);

	BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
	HttpHeaders headers = new HttpHeaders();
	headers.putAll(exchange.getRequest().getHeaders());
	headers.remove(HttpHeaders.CONTENT_LENGTH);
	MyCachedBodyOutputMessage outputMessage = new MyCachedBodyOutputMessage(exchange, headers);
	ServerHttpRequest.Builder requestBuilder = exchange.getRequest().mutate();
	requestBuilder.headers(k -> k.remove("Content-length"));

	Mono mono = bodyInserter.insert(outputMessage, new BodyInserterContext())
			.then(Mono.defer(() -> {
				//解决body内数据过长读取不完整的问题
				Flux<DataBuffer> body = outputMessage.getBody();
				DataBufferHolder holder = new DataBufferHolder();
				try{
					body.subscribe(dataBuffer -> {
						int len = dataBuffer.readableByteCount();
						holder.length = len;
						byte[] bytes = new byte[len];
						dataBuffer.read(bytes);
						DataBufferUtils.release(dataBuffer);
						String oldBody = new String(bytes, StandardCharsets.UTF_8);
						JsonNode jsonNode = readNode(oldBody);
					 	checkTokenAndSaveUser((ObjectNode)jsonNode);
						DataBuffer data = outputMessage.bufferFactory().allocateBuffer();
						data.write(jsonNode.toString().getBytes(StandardCharsets.UTF_8));
						holder.length = data.readableByteCount();
						holder.dataBuffer=data;
					});

				}catch (Exception e){
					if(e.getCause() instanceof ServiceException){
						ServiceException e1 = (ServiceException) e.getCause();
						return handleFailedRequest(exchange, JSONObject.toJSONString(CommonResponse.error(e1.getCode(), e1.getMessage())));
					}
					return handleFailedRequest(exchange, JSONObject.toJSONString(CommonResponse.error(SYSTEM_ERROR.getCode(), SYSTEM_ERROR.getMessage())));
				}


				ServerHttpRequestDecorator decorator = newDecorator(exchange,holder.length, Flux.just(holder.dataBuffer));
				return chain.filter(exchange.mutate().request(decorator).build());

			}));

		return mono;
	}

	private void checkTokenAndSaveUser(ObjectNode oldDataJSON) throws ServiceException{
		JsonNode token = oldDataJSON.get("token");
		if(token==null){
			throw new ServiceException(TOKEN_NOT_EXISTENT_ERROR.getCode(), TOKEN_NOT_EXISTENT_ERROR.getMessage());
		}
		Object userIdCacheKey = redisUtil.get(token.asText());
		if(userIdCacheKey!=null){
			Object cacheInfo = redisUtil.get(userIdCacheKey+"");
			UserCacheBO cacheDataObj = null;
			if(cacheInfo!=null){
				cacheDataObj = (UserCacheBO) cacheInfo;
			}else{
				cacheDataObj = userManager.flushUserCache(userIdCacheKey+"",token.asText());
			}
			UserBO userBO = userConvert.cacheToBo(cacheDataObj);
			try {
				String s = JSON.toJSONString(userBO);
				JsonNode node = objectMapper.readTree(s);
				oldDataJSON.set("userBO",node);
			} catch (IOException e) {
				e.printStackTrace();
				throw new IllegalStateException(e);
			}
		}else{
			throw new ServiceException(TOKEN_NOT_EXISTENT_ERROR.getCode(), TOKEN_NOT_EXISTENT_ERROR.getMessage());
		}
	}


	private Mono<Void> handleFailedRequest(ServerWebExchange exchange, String message) {
		byte[] bytes = message.getBytes(StandardCharsets.UTF_8);
		DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
		exchange.getResponse().setStatusCode(HttpStatus.OK);
		return exchange.getResponse().writeWith(Flux.just(buffer));
	}

	private JsonNode readNode(String in) {
		try {
			return objectMapper.readTree(in);
		} catch (Exception e) {
			throw new IllegalStateException(e);
		}
	}

	private class DataBufferHolder {
		DataBuffer dataBuffer;
		int length;
	}

	/**
	 * 修改form参数
	 * @param contentType 请求类型
	 * @param bodyString  请求body信息
	 */
	@SneakyThrows
	public static String addPara(String contentType, String bodyString) {
		StringBuffer stringBuffer = new StringBuffer();

		String boundary = contentType.substring(contentType.lastIndexOf("boundary=") + 9);//获取随机字符传信息
		String boundary_end = StrUtil.format("--{}--\r\n", boundary);
		Map<String, Object> formMap = Maps.newHashMap();
		/**
		 *
		 * 根据自己需求进行对bodyString信息修改,例如下面,根据boundary对传入的bodyString进行了分割
		 *  String[] split = bodyString.split(boundary);
		 *  然后将修改完后的信息封装到formMap中,需要注意的是,file文件需要以new FileResource(file, fileName)的形式当作value放到formMap中
		 */
		String part = "^\r\nContent-Disposition: form-data; name=\"([^/?]+)\"\r\n\r\n([^/?]+)\r\n--?$";
		Pattern r = Pattern.compile(part);
		String[] split = bodyString.split(boundary);
		for(int x=1;x<split.length-1;x++){
			Matcher m = r.matcher(split[x]);
			if(m.find()){
				String name = m.group(1);
				String value = m.group(2);
				System.out.println("name:"+name+" value:"+value);
//				formMap.put(name,value);
			}
		}

		formMap.put("ft",11111);
		formMap.put("tcu",22222);
		Integer count =0;
		for (Map.Entry<String, Object> entry : formMap.entrySet()) {
			stringBuffer.append(appendPart(boundary, entry.getKey(), entry.getValue(),count));
			count++;
		}
		stringBuffer.append(boundary_end);//拼接结束信息
		log.info(stringBuffer.toString());

		return stringBuffer.toString();
	}

	public ServerHttpRequestDecorator newDecorator(ServerWebExchange exchange,long dataLength,Flux<DataBuffer> body){
		return new ServerHttpRequestDecorator(
				exchange.getRequest()) {
			@Override
			public HttpHeaders getHeaders() {
			//数据长度变了以后 需要修改header里的数据,不然接收数据时会异常
			//我看别人说删除会自动补充数据长度,但我这个版本不太行
//				long contentLength = headers.getContentLength();
				HttpHeaders httpHeaders = new HttpHeaders();
				httpHeaders.putAll(super.getHeaders());
//				if (contentLength > 0) {
					httpHeaders.setContentLength(dataLength);
//				} else {
//					httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
//				}
				return httpHeaders;
			}

			@Override
			public Flux<DataBuffer> getBody() {
				return body;
			}
		};
	}


	/**
	 * 添加Multipart表单的数据项
	 *
	 * @param boundary      随机串信息
	 * @param formFieldName 表单名
	 * @param value         值,可以是普通值、资源(如文件等)
	 */
	private static String appendPart(String boundary, String formFieldName, Object value,Integer count) throws IORuntimeException {
		StringBuffer stringBuffer = new StringBuffer();
		// 多资源
		if (value instanceof MultiResource) {
			for (Resource subResource : (MultiResource) value) {
				appendPart(boundary, formFieldName, subResource,count);
			}
			return stringBuffer.toString();
		}

		if(count!=0){
			stringBuffer.append("--").append(boundary).append(StrUtil.CRLF);
		}else{
			stringBuffer.append(StrUtil.CRLF);
//			stringBuffer.append(boundary).append(StrUtil.CRLF);
		}

		if (value instanceof Resource) {
			// 文件资源(二进制资源)
			final Resource resource = (Resource) value;
			final String fileName = resource.getName();
			stringBuffer.append(StrUtil.format(CONTENT_DISPOSITION_FILE_TEMPLATE, formFieldName, ObjectUtil.defaultIfNull(fileName, formFieldName)));
			// 根据name的扩展名指定互联网媒体类型,默认二进制流数据
			stringBuffer.append(StrUtil.format(CONTENT_TYPE_FILE_TEMPLATE, HttpUtil.getMimeType(fileName, "application/octet-stream")));
		} else {
			// 普通数据
			stringBuffer.append(StrUtil.format(CONTENT_DISPOSITION_TEMPLATE, formFieldName)).append(value);
		}
		stringBuffer.append(StrUtil.CRLF);
		return stringBuffer.toString();
	}
}


MyCachedBodyOutputMessage.java

import java.util.function.Supplier;
import org.reactivestreams.Publisher;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public class MyCachedBodyOutputMessage implements ReactiveHttpOutputMessage {
    private final DataBufferFactory bufferFactory;
    DataBuffer dataBuffer;
    private final HttpHeaders httpHeaders;
    private Flux<DataBuffer> body = Flux.error(new IllegalStateException("The body is not set. Did handling complete with success?"));

    public MyCachedBodyOutputMessage(ServerWebExchange exchange, HttpHeaders httpHeaders) {
        this.bufferFactory = exchange.getResponse().bufferFactory();
        this.httpHeaders = httpHeaders;
    }
    @Override
    public void beforeCommit(Supplier<? extends Mono<Void>> action) {
    }
    @Override
    public boolean isCommitted() {
        return false;
    }
    @Override
    public HttpHeaders getHeaders() {
        return this.httpHeaders;
    }
    @Override
    public DataBufferFactory bufferFactory() {
        return this.bufferFactory;
    }

    public Flux<DataBuffer> getBody() {
        return this.body;
    }
    @Override
    public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
        this.body = Flux.from(body);
        return Mono.empty();
    }

    @Override
    public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
        return this.writeWith(Flux.from(body).flatMap((p) -> {
            return p;
        }));
    }
    @Override
    public Mono<Void> setComplete() {
        return this.writeWith(Flux.empty());
    }
}

修改返回值代码


import com.google.common.base.Joiner;
import com.google.common.base.Throwables;
import org.apache.commons.lang3.StringUtils;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPOutputStream;

import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR;


@Component
public class ResponseFilter implements GlobalFilter, Ordered {

    private static final Logger log = LoggerFactory.getLogger(ResponseFilter.class);
    private static Joiner joiner = Joiner.on("");
//    @Autowired
//    private IgnoreWhiteProperties ignoreWhite;
    /**
     * 约定的压缩格式
     */
    private final static String GZIP = "gzip";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        String acceptEncoding = exchange.getRequest().getHeaders().getFirst("Accept-Encoding");

        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();

        ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
                    // 获取ContentType,判断是否返回JSON格式数据
                    String originalResponseContentType = exchange.getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);
                    if (StringUtils.isNotBlank(originalResponseContentType) && originalResponseContentType.contains("application/json")) {
                        Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                        //(返回数据内如果字符串过大,默认会切割)解决返回体分段传输
                        return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                            List<String> list = new ArrayList<>();
                            dataBuffers.forEach(dataBuffer -> {
                                try {
                                    byte[] content = new byte[dataBuffer.readableByteCount()];
                                    dataBuffer.read(content);
                                    DataBufferUtils.release(dataBuffer);
                                    list.add(new String(content, StandardCharsets.UTF_8));
                                } catch (Exception e) {
                                    log.info("加载Response字节流异常,失败原因:{}", Throwables.getStackTraceAsString(e));
                                }
                            });
                            String responseData = joiner.join(list);
                            System.out.println("responseData:"+responseData);
                            String responseDataEncode = null;
//                            String responseDataEncode = AESUtil.aesEncodeByKey(responseData, "MP5v0^zee5Qlgq5V");
                            if(responseDataEncode==null){
                                return bufferFactory.wrap(responseData.getBytes(StandardCharsets.UTF_8));
                            }
                            responseDataEncode =  responseDataEncode.replaceAll("\r\n", "").replaceAll("\n","");
                            byte[] uppedContent = new String(responseDataEncode.getBytes(), StandardCharsets.UTF_8).getBytes();
                            originalResponse.getHeaders().setContentLength(uppedContent.length);

                            if(!StringUtils.isAnyBlank(acceptEncoding)){
                                assert acceptEncoding != null;
                                //是否支持压缩
                                if(acceptEncoding.contains(GZIP)){
                                    //支持压缩
                                    ByteArrayOutputStream bout = new ByteArrayOutputStream();
                                    //压缩输出流中的数据
                                    GZIPOutputStream gout;
                                    try {
                                        gout = new GZIPOutputStream(bout);
                                        gout.write(uppedContent);
                                        gout.close();
                                        uppedContent = bout.toByteArray();
                                        originalResponse.getHeaders().setContentLength(uppedContent.length);
                                        originalResponse.getHeaders().set("content-encoding", GZIP);
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                }else{
                                    originalResponse.getHeaders().setContentLength(uppedContent.length);
                                }
                            }
                            return bufferFactory.wrap(uppedContent);
                        }));
                    }
                }
                return super.writeWith(body);
            }

        };

        return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

}

参考文章:https://blog.csdn.net/Hardworking666/article/details/123833192文章来源地址https://www.toymoban.com/news/detail-597146.html

到了这里,关于Spring-Cloud-Gateway修改请求(json,form带文件请求)参数,返回值参数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring-Cloud-Gateway如何自定义路由过滤器?

    遇到这么一个面试题:自定义网关过滤器实现把url中的请求参数放到http的header中传递给微服务。 我们知道网关的一个重要的作用就是路由转发,路由表的配置大概是这个样子: 其中的filters就是配置的路由过滤器,Spring已经内置了31个路由的过滤器,这些过滤器都是 org.spring

    2024年02月16日
    浏览(32)
  • spring-cloud-gateway版本和springboot版本不匹配

    在搭建gateway服务的时候,启动出现以下问题: Description: An attempt was made to call a method that does not exist. The attempt was made from the following location:     org.springframework.cloud.gateway.config.GatewayAutoConfiguration$NettyConfiguration.buildConnectionProvider(GatewayAutoConfiguration.java:798) The following method did no

    2024年02月16日
    浏览(92)
  • 芝法酱躺平攻略(14)——Nginx与Spring-Cloud-Gateway

    上一章芝法酱躺平攻略(12)展望了微服务下常见的技术需求与常见解决方案,本期来讲解第一部分,Nginx与SpringCloud-Gateway。 本章将实践在nginx和spring-cloud-gateway的简单使用。 首先,去官网查找最新稳定版,把下载的nginx包放到DOWNLOAD文件夹下。 而后把该包解压到SOFTWARE文件夹

    2024年02月07日
    浏览(29)
  • 【深入解析spring cloud gateway】05 gateway请求转发实验

    三个工程: eureka-server eureka-client gateway 实验目的:通过网关访问对应的微服务:eureka-client。gateway和eureka-client注册到eureka-server上 eureka-server略 eureka-client application.yml 提供一个接口 pom.xml application.yml 定义一个filter用于去掉路径中的/gateway 自定义一个GlobalFilter,用于去掉路径

    2024年02月10日
    浏览(40)
  • 修改经过Spring Gateway的Json数据

    使用Spring Cloud Gateway作为网关时经常会需要对报文内的json数据进行修改,但是目前看到的实现方法看起来都很复杂,这里提供一种使用Spring官方提供的ModifyRequestBodyGatewayFilterFactory类来修改json报文的方法 Spring Boot版本:2.7.15 Hutool: 5.8.21 Java: 11 实现分为两个部分 filter:在自定义

    2024年02月08日
    浏览(22)
  • 【Spring Cloud】网关Gateway的请求过滤工厂RequestRateLimiterGatewayFilterFactory

            关于微服务网关Gateway中有几十种过滤工厂,这一篇博文记录的是关于请求限流过滤工厂,也就是标题中的RequestRateLimiterGatewayFilterFactory。这个路由过滤工厂是 用来判断当前请求是否应该被处理,如果不会被处理就会返回HTTP状态码为429的code 。接下来构建两个模块,

    2024年02月07日
    浏览(26)
  • 修改经过Spring Gateway的表单中的Json数据

    使用Spring Cloud Gateway作为网关时有时候一个请求是既包含excel又包含json的表单数据,出于各种层面考虑网关需要获取并更新其中的json数据 Spring Boot版本:2.7.15 Hutool: 5.8.21 Java: 11 实现分为2个部分 使用上文提到的ModifyRequestBodyGatewayFilterFactory类来修改请求体,这样最后就不用我们

    2024年02月08日
    浏览(30)
  • 从Spring Cloud Gateway过滤器中获取请求体的最优方案

    在spring cloud gateway出现这个问题的时候我们第一反应应该很简单,但是真正实现的时候却有点困难。我看了很多相关的文档,感觉太多都不清晰而且解决不了问题。下面我就把我的方便理解的解决方案写下来。 1. 先重写请求体(过滤器优先级一定要在要获取body之前执行) 这

    2024年02月16日
    浏览(37)
  • spring cloud gateway中出现503 spring cloud gateway中出现503

    当搭建网关模块的时候出现503的错误的最大的可能就是没有设置负载均衡的依赖包  原先搭建的时候采用的是下面的方式进行设置的 上面的这种方式可以直接进行注册和发现,但是要求必须导入下面的依赖 希望简单的随笔能够帮助你!

    2024年02月11日
    浏览(28)
  • POST请求中json和form的优缺点

    互为对方的优缺点 请求方式 Content-Type 优点 缺点 form multipart/form-data 支持传文件、易编写、Postman调试方便 不支持嵌套类型 json application/json 支持嵌套类型 编写麻烦 为什么接口设计都不用普通 POST 如何设置APIFlask入参字段为嵌套字段 Java接口传参时用form data好还是用json好?

    2024年02月13日
    浏览(18)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包