package com.learn.filter;
import com.google.gson.Gson;
import com.learn.utils.ErrorType;
import com.learn.utils.MD5Util;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.factory.rewrite.RewriteFunction;
import org.springframework.cloud.gateway.support.BodyInserterContext;
import org.springframework.cloud.gateway.support.CachedBodyOutputMessage;
import org.springframework.cloud.gateway.support.DefaultServerRequest;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
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.ServerRequest;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
@Component
public class CtokenGatewayFilter extends AbstractGatewayFilterFactory<CtokenGatewayFilter.Config> {
public CtokenGatewayFilter() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerRequest serverRequest = new DefaultServerRequest(exchange);
System.out.println("访问路径============" + serverRequest.uri().getPath());
HttpHeaders headers = exchange.getRequest().getHeaders();
List<String> errorList = headers.get("bodystr");
if (null == errorList || errorList.size() == 0) {
Flux<HashMap> bodyToFlux = serverRequest.bodyToFlux(config.inClass);
Gson gson = new Gson();
AtomicReference<String> bodyRef = new AtomicReference<>();
DefaultDataBufferFactory defaultDataBuffer = new DefaultDataBufferFactory();
bodyToFlux.map(o -> {
System.out.println("class=======" + o.getClass());
System.out.println("o 的value=====" + gson.toJson(o));
return o;
}).subscribe();
String bodyStr = bodyRef.get();
Message message = checkCtoken(headers, bodyStr);
System.out.println("请求数据===========" + bodyStr);
if (null != message) {
// 写出校验错误结果
return exchange.getResponse().writeWith(messageBufferFlux);
} else {
// 重建请求 防止报错
return chain.filter(exchange.mutate().request(decorator).build());
}
} else {
return chain.filter(exchange);
}
};
}
/**
* 检查ctoken
* @param headers 请求头
* @return 校验结果
*/
@SuppressWarnings("unchecked")
private Message checkCtoken(HttpHeaders headers, String httpEntity) {
Message message;
List<String> tokenList = headers.get("token");
List<String> partneridList = headers.get("partnerid");
List<String> memberidList = headers.get("memberid");
List<String> timestampList = headers.get("timestamp");
List<String> ctokenList = headers.get("ctoken");
message = validParams(tokenList, partneridList, memberidList, ctokenList);
if (null != message) {
return message;
}
String token = tokenList.get(0);
String partnerid = partneridList.get(0);
String memberid = memberidList.get(0);
String timestamp = timestampList.get(0);
String ctoken = ctokenList.get(0);
String validCToken = getCtoken(partnerid, memberid, timestamp, token, httpEntity);
if (!validCToken.equalsIgnoreCase(ctoken)) {
message = new Message();
message.setResult(ErrorType.CH_PAEAM_ERROR);
message.setMsg("非法的参数");
}
return message;
}
@Override
public String name() {
return "ctoken";
}
@Override
public List<String> shortcutFieldOrder() {
return Collections.singletonList("ctoken");
}
public static class Config {
private boolean enabled;
private Class inClass = HashMap.class;
private Class outClass = HashMap.class;
private RewriteFunction rewriteFunction = (exchange, bodyMap) -> {
HashMap<String, Object> valueMap = (HashMap<String, Object>) bodyMap;
String vin = (String) valueMap.get("vin");
System.out.println("uname===========" + valueMap.get("uname"));
valueMap.put("name", "zhangsan");
valueMap.put("age", 18);
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("msg", "校验错误");
resultMap.put("result", 99);
return Mono.just(resultMap);
};
public RewriteFunction getRewriteFunction() {
return rewriteFunction;
}
public void setRewriteFunction(RewriteFunction rewriteFunction) {
this.rewriteFunction = rewriteFunction;
}
public Class getInClass() {
return inClass;
}
public void setInClass(Class inClass) {
this.inClass = inClass;
}
public Class getOutClass() {
return outClass;
}
public void setOutClass(Class outClass) {
this.outClass = outClass;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
}
访问路径============/user/getUserById // 这是第一次请求
请求数据===========null
判断结果{"msg":"非法参数","result":99}
//下面的错误时其它代码导致的
2019-01-10 22:01:42.237 WARN 35400 --- [ctor-http-nio-3] io.netty.util.concurrent.DefaultPromise : An exception was thrown by reactor.ipc.netty.http.server.HttpServerHandler$TerminateHttpHandler.operationComplete()
reactor.core.Exceptions$ErrorCallbackNotImplemented: org.springframework.core.codec.DecodingException: JSON decoding error: Unexpected end-of-input: was expecting rest of token (internal state: 4); nested exception is com.fasterxml.jackson.core.io.JsonEOFException: Unexpected end-of-input: was expecting rest of token (internal state: 4)
at [Source: UNKNOWN; line: 28, column: 5]
Caused by: org.springframework.core.codec.DecodingException: JSON decoding error: Unexpected end-of-input: was expecting rest of token (internal state: 4); nested exception is com.fasterxml.jackson.core.io.JsonEOFException: Unexpected end-of-input: was expecting rest of token (internal state: 4)
at [Source: UNKNOWN; line: 28, column: 5]
at org.springframework.http.codec.json.Jackson2Tokenizer.endOfInput(Jackson2Tokenizer.java:117) ~[spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at reactor.core.publisher.FluxMapSignal$FluxMapSignalSubscriber.onComplete(FluxMapSignal.java:199) ~[reactor-core-3.1.10.RELEASE.jar:3.1.10.RELEASE]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:130) ~[reactor-core-3.1.10.RELEASE.jar:3.1.10.RELEASE]
at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:245) ~[reactor-core-3.1.10.RELEASE.jar:3.1.10.RELEASE]
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:130) ~[reactor-core-3.1.10.RELEASE.jar:3.1.10.RELEASE]
at reactor.ipc.netty.channel.FluxReceive.terminateReceiver(FluxReceive.java:380) ~[reactor-netty-0.7.10.RELEASE.jar:0.7.10.RELEASE]
at reactor.ipc.netty.channel.FluxReceive.drainReceiver(FluxReceive.java:204) ~[reactor-netty-0.7.10.RELEASE.jar:0.7.10.RELEASE]
at reactor.ipc.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:345) ~[reactor-netty-0.7.10.RELEASE.jar:0.7.10.RELEASE]
at reactor.ipc.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:338) [reactor-netty-0.7.10.RELEASE.jar:0.7.10.RELEASE]
at reactor.ipc.netty.channel.ChannelOperations.onHandlerTerminate(ChannelOperations.java:404) [reactor-netty-0.7.10.RELEASE.jar:0.7.10.RELEASE]
at reactor.ipc.netty.http.server.HttpServerOperations.cleanHandlerTerminate(HttpServerOperations.java:473) [reactor-netty-0.7.10.RELEASE.jar:0.7.10.RELEASE]
at reactor.ipc.netty.http.server.HttpServerHandler$TerminateHttpHandler.operationComplete(HttpServerHandler.java:330) ~[reactor-netty-0.7.10.RELEASE.jar:0.7.10.RELEASE]
at reactor.ipc.netty.http.server.HttpServerHandler$TerminateHttpHandler.operationComplete(HttpServerHandler.java:320) ~[reactor-netty-0.7.10.RELEASE.jar:0.7.10.RELEASE]
at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:511) [netty-common-4.1.29.Final.jar:4.1.29.Final]
at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:485) [netty-common-4.1.29.Final.jar:4.1.29.Final]
at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:424) [netty-common-4.1.29.Final.jar:4.1.29.Final]
at io.netty.util.concurrent.DefaultPromise.trySuccess(DefaultPromise.java:103) [netty-common-4.1.29.Final.jar:4.1.29.Final]
at io.netty.util.internal.PromiseNotificationUtil.trySuccess(PromiseNotificationUtil.java:48) [netty-common-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.ChannelOutboundBuffer.safeSuccess(ChannelOutboundBuffer.java:696) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.ChannelOutboundBuffer.remove(ChannelOutboundBuffer.java:258) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.ChannelOutboundBuffer.removeBytes(ChannelOutboundBuffer.java:338) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.socket.nio.NioSocketChannel.doWrite(NioSocketChannel.java:411) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannel$AbstractUnsafe.flush0(AbstractChannel.java:934) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.flush0(AbstractNioChannel.java:360) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannel$AbstractUnsafe.flush(AbstractChannel.java:901) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.flush(DefaultChannelPipeline.java:1396) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:768) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:749) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.flush(CombinedChannelDuplexHandler.java:533) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.ChannelOutboundHandlerAdapter.flush(ChannelOutboundHandlerAdapter.java:115) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.CombinedChannelDuplexHandler.flush(CombinedChannelDuplexHandler.java:358) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:768) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:749) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.ChannelDuplexHandler.flush(ChannelDuplexHandler.java:117) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush(AbstractChannelHandlerContext.java:768) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.flush(AbstractChannelHandlerContext.java:749) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at reactor.ipc.netty.channel.ChannelOperationsHandler.doWrite(ChannelOperationsHandler.java:300) [reactor-netty-0.7.10.RELEASE.jar:0.7.10.RELEASE]
at reactor.ipc.netty.channel.ChannelOperationsHandler.drain(ChannelOperationsHandler.java:476) [reactor-netty-0.7.10.RELEASE.jar:0.7.10.RELEASE]
at reactor.ipc.netty.channel.ChannelOperationsHandler.flush(ChannelOperationsHandler.java:194) [reactor-netty-0.7.10.RELEASE.jar:0.7.10.RELEASE]
at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0(AbstractChannelHandlerContext.java:776) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:802) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:814) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:794) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:831) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.DefaultChannelPipeline.writeAndFlush(DefaultChannelPipeline.java:1071) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.AbstractChannel.writeAndFlush(AbstractChannel.java:300) [netty-transport-4.1.29.Final.jar:4.1.29.Final]
at reactor.ipc.netty.http.server.HttpServerOperations.onOutboundComplete(HttpServerOperations.java:451) [reactor-netty-0.7.10.RELEASE.jar:0.7.10.RELEASE]
at reactor.ipc.netty.channel.ChannelOperations.onComplete(ChannelOperations.java:221) [reactor-netty-0.7.10.RELEASE.jar:0.7.10.RELEASE]
at reactor.core.publisher.MonoPeekTerminal$MonoTerminalPeekSubscriber.onComplete(MonoPeekTerminal.java:321) [reactor-core-3.1.10.RELEASE.jar:3.1.10.RELEASE]
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableConditionalSubscriber.onComplete(FluxPeekFuseable.java:555) [reactor-core-3.1.10.RELEASE.jar:3.1.10.RELEASE]
at reactor.core.publisher.Operators$MonoSubscriber.onComplete(Operators.java:1121) [reactor-core-3.1.10.RELEASE.jar:3.1.10.RELEASE]
at reactor.core.publisher.MonoIgnoreThen$ThenAcceptInner.onComplete(MonoIgnoreThen.java:313) [reactor-core-3.1.10.RELEASE.jar:3.1.10.RELEASE]
at reactor.core.publisher.Operators.complete(Operators.java:128) [reactor-core-3.1.10.RELEASE.jar:3.1.10.RELEASE]
at reactor.core.publisher.MonoEmpty.subscribe(MonoEmpty.java:45) [reactor-core-3.1.10.RELEASE.jar:3.1.10.RELEASE]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) [reactor-core-3.1.10.RELEASE.jar:3.1.10.RELEASE]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:153) [reactor-core-3.1.10.RELEASE.jar:3.1.10.RELEASE]
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56) [reactor-core-3.1.10.RELEASE.jar:3.1.10.RELEASE]
at reactor.core.publisher.MonoPeekFuseable.subscribe(MonoPeekFuseable.java:70) [reactor-core-3.1.10.RELEASE.jar:3.1.10.RELEASE]
at reactor.core.publisher.MonoPeekTerminal.subscribe(MonoPeekTerminal.java:61) [reactor-core-3.1.10.RELEASE.jar:3.1.10.RELEASE]
at reactor.ipc.netty.channel.ChannelOperations.applyHandler(ChannelOperations.java:381) [reactor-netty-0.7.10.RELEASE.jar:0.7.10.RELEASE]
at reactor.ipc.netty.http.server.HttpServerOperations.onHandlerStart(HttpServerOperations.java:399) [reactor-netty-0.7.10.RELEASE.jar:0.7.10.RELEASE]
at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163) ~[netty-common-4.1.29.Final.jar:4.1.29.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404) ~[netty-common-4.1.29.Final.jar:4.1.29.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:446) ~[netty-transport-4.1.29.Final.jar:4.1.29.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884) ~[netty-common-4.1.29.Final.jar:4.1.29.Final]
at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_181]
Caused by: com.fasterxml.jackson.core.io.JsonEOFException: Unexpected end-of-input: was expecting rest of token (internal state: 4)
at [Source: UNKNOWN; line: 28, column: 5]
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportInvalidEOF(ParserMinimalBase.java:594) ~[jackson-core-2.9.7.jar:2.9.7]
at com.fasterxml.jackson.core.json.async.NonBlockingJsonParser._finishTokenWithEOF(NonBlockingJsonParser.java:399) ~[jackson-core-2.9.7.jar:2.9.7]
at com.fasterxml.jackson.core.json.async.NonBlockingJsonParser.nextToken(NonBlockingJsonParser.java:162) ~[jackson-core-2.9.7.jar:2.9.7]
at org.springframework.http.codec.json.Jackson2Tokenizer.parseTokenBufferFlux(Jackson2Tokenizer.java:128) ~[spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
at org.springframework.http.codec.json.Jackson2Tokenizer.endOfInput(Jackson2Tokenizer.java:113) ~[spring-web-5.0.10.RELEASE.jar:5.0.10.RELEASE]
... 68 common frames omitted
访问路径============/user/getUserById //这是第二次请求
class=======class java.util.HashMap
o 的value====={"result":0,"msg":"获取订单列表成功","data":{}
请求数据===========null
判断结果{"msg":"非法参数","result":99}
首先定义一个filter,在这个Filter中获取body,实现方式和官方的ModifyRequestBodyGatewayFilterFactory类几乎一样,在这个实现中,把读取到的body放到header中,如下:
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerRequest request = new DefaultServerRequest(exchange);
Class inClass = config.getInClass();
Gson gson = new Gson();
AtomicReference<String> bodyStr = new AtomicReference<>();
Mono<?> modifiedBody = request.bodyToMono(inClass).flatMap(o -> {
bodyStr.set(gson.toJson(o));
return config.rewriteFunction.apply(exchange, o);
});
BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, config.outClass);
CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, exchange.getRequest().getHeaders());
HttpHeaders headers = new HttpHeaders();
headers.putAll(exchange.getRequest().getHeaders());
headers.remove("Content-Length");
if (config.getContentType() != null) {
headers.set("Content-Type", config.getContentType());
}
return bodyInserter.insert(outputMessage, new BodyInserterContext()).then(Mono.defer(() -> {
ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
public HttpHeaders getHeaders() {
String str = bodyStr.get();
System.out.println("str===========" + str); // 这里
long contentLength = headers.getContentLength();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.putAll(super.getHeaders());
httpHeaders.set("bodystr", str); // 这里
if (contentLength > 0L) {
httpHeaders.setContentLength(contentLength);
} else {
httpHeaders.set("Transfer-Encoding", "chunked");
}
return httpHeaders;
}
public Flux<DataBuffer> getBody() {
return outputMessage.getBody();
}
};
return chain.filter(exchange.mutate().request(decorator).build());
}));
};
}