android系统定制开发Spring Cloud Gateway 读取请求传参

背景介绍

android系统定制开发有个业务需求,android系统定制开发要提供一套接口给第三方调用。

在处理具体业务接口之前,设计上要先做个简单的鉴权,协商拟定了身份传参后,考虑到项目上已经用到了Spring Cloud Gateway ,就统一在模块做身份校验。

所以在服务端获取到请求的时候,要先拦截获取到请求传参,才能做后续的鉴权逻辑。

这里就需要解决一个问题:Spring Cloud Gateway 怎么读取请求传参?

搜索关键词:spring cloud gateway get request body

问题描述

问题:Spring Cloud Gateway 读取请求传参

这里只简单处理两种情况,get请求和post请求。

如果发现是get请求,就取url上的参数;
如果发现是post请求,就读取body的内容。

解决方案

参考 https://github.com/spring-cloud/spring-cloud-gateway/issues/747

定义了两个过滤器 filter,第一个过滤器ApiRequestFilter获取参数,放到上下文 GatewayContext

注意如果是POST请求,请求体读取完后,要重新构造,填回请求体中。

第二个过滤器ApiVerifyFilter, 从上下文可以直接获取到参数。

后面如果其他业务也有读取参数的需求,就直接从上下文获取,不用再重复写获取参数的逻辑。

实现代码

GatewayContext

@Datapublic class GatewayContext {    public static final String CACHE_GATEWAY_CONTEXT = "cacheGatewayContext";    /**     * cache json body     */    private String cacheBody;    /**     * cache form data     */    private MultiValueMap<String, Part> formData;    /**     * cache request path     */    private String path;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

ApiRequestFilter

@Component@Slf4jpublic class ApiRequestFilter implements GlobalFilter, Ordered {    private static AntPathMatcher antPathMatcher;    static {        antPathMatcher = new AntPathMatcher();    }    /**     * default HttpMessageReader     */    private static final List<HttpMessageReader<?>> messageReaders = HandlerStrategies.withDefaults().messageReaders();    private static final ResolvableType MULTIPART_DATA_TYPE = ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, Part.class);    private static final Mono<MultiValueMap<String, Part>> EMPTY_MULTIPART_DATA = Mono.just(CollectionUtils.unmodifiableMultiValueMap(new LinkedMultiValueMap<String, Part>(0))).cache();    @Override    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {        ServerHttpRequest request = exchange.getRequest();        String url = request.getURI().getPath();        if(request.getMethod() == HttpMethod.GET){            // get请求 处理参数            return handleGetMethod(exchange, chain, request);        }        if(request.getMethod() == HttpMethod.POST){            // post请求 处理参数            return handlePostMethod(exchange, chain, request);        }        return chain.filter(exchange);    }    /**     * get请求 处理参数     * @param exchange     * @param chain     * @param request     * @return     */    private Mono<Void> handleGetMethod(ServerWebExchange exchange, GatewayFilterChain chain, ServerHttpRequest request) {        // TODO 暂时不做处理        return chain.filter(exchange);    }    /**     * post请求 校验参数     * @param exchange     * @param chain     * @param request     * @return     */    private Mono<Void> handlePostMethod(ServerWebExchange exchange, GatewayFilterChain chain, ServerHttpRequest request){        GatewayContext gatewayContext = new GatewayContext();        gatewayContext.setPath(request.getPath().pathWithinApplication().value());        /**         * save gateway context into exchange         */        exchange.getAttributes().put(GatewayContext.CACHE_GATEWAY_CONTEXT, gatewayContext);        MediaType contentType = request.getHeaders().getContentType();        if(MediaType.APPLICATION_JSON.equals(contentType)                || MediaType.APPLICATION_JSON_UTF8.equals(contentType)){            // 请求内容为 application json            // 重新构造 请求体            return readJsonBody(exchange, chain, gatewayContext);        }        if (MediaType.MULTIPART_FORM_DATA.isCompatibleWith(contentType)) {            // 请求内容为 form data            return readFormData(exchange, chain, gatewayContext);        }        return chain.filter(exchange);    }    /**     * post 请求     * 重新构造 请求体     * @param exchange     * @param chain     * @param gatewayContext     * @return     */    private Mono<Void> readJsonBody(ServerWebExchange exchange, GatewayFilterChain chain, GatewayContext gatewayContext) {        return DataBufferUtils.join(exchange.getRequest().getBody())                .flatMap(dataBuffer -> {                    /*                     * read the body Flux<DataBuffer>, and release the buffer                     * //TODO when SpringCloudGateway Version Release To G.SR2,this can be update with the new version's feature                     * see PR https://github.com/spring-cloud/spring-cloud-gateway/pull/1095                     */                    byte[] bytes = new byte[dataBuffer.readableByteCount()];                    dataBuffer.read(bytes);                    DataBufferUtils.release(dataBuffer);                    Flux<DataBuffer> cachedFlux = Flux.defer(() -> {                        DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);                        DataBufferUtils.retain(buffer);                        return Mono.just(buffer);                    });                    /**                     * repackage ServerHttpRequest                     */                    ServerHttpRequest mutatedRequest =                            new ServerHttpRequestDecorator(exchange.getRequest()) {                                @Override                                public Flux<DataBuffer> getBody() {                                    return cachedFlux;                                }                            };                    /**                     * mutate exchage with new ServerHttpRequest                     */                    ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build();                    /**                     * read body string with default messageReaders                     */                    return ServerRequest.create(mutatedExchange, messageReaders)                            .bodyToMono(String.class)                            .doOnNext(objectValue -> {                                // save body into gatewayContext                                gatewayContext.setCacheBody(objectValue);                            })                            .then(chain.filter(mutatedExchange));                });    }    private Mono<Void> readFormData(ServerWebExchange exchange, GatewayFilterChain chain, GatewayContext gatewayContext) {        return exchange.getRequest().getBody().collectList().flatMap(dataBuffers -> {            final byte[] totalBytes = dataBuffers.stream().map(dataBuffer -> {                try {                    final byte[] bytes = IOUtils.toByteArray(dataBuffer.asInputStream());//                    System.out.println(new String(bytes));                    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()) {                    // 如果为文件时 则进入下一次循环                    if (key.equals("file")) {                        continue;                    }                    part.getFirst(key).content().subscribe(buffer -> {                        final byte[] bytes = new byte[buffer.readableByteCount()];                        buffer.read(bytes);                        DataBufferUtils.release(buffer);                        try {                            final String bodyString = new String(bytes, "utf-8");                            gatewayContext.setCacheBody(bodyString);                        } catch (UnsupportedEncodingException e) {                            e.printStackTrace();                        }                    });                }                return chain.filter(exchange.mutate().request(decorator).build());            });        });    }    @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;    }    /**     * addBytes.     * @param first first     * @param second second     * @return byte     */    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;    }    private DataBuffer buffer(byte[] bytes) {        final NettyDataBufferFactory nettyDataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);        final DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);        buffer.write(bytes);        return buffer;    }    @Override    public int getOrder() {        return FilterOrderConstant.getOrder(this.getClass().getName());    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216

ApiVerifyFilter

@Component@Slf4jpublic class ApiVerifyFilter implements GlobalFilter, Ordered {    @Override    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {        ServerHttpRequest request = exchange.getRequest();        String url = request.getURI().getPath();		        if(request.getMethod() == HttpMethod.GET){            // get请求 校验参数            return verifyGetMethod(exchange, chain, request);        }        if(request.getMethod() == HttpMethod.POST){            // post请求 校验参数            return verifyPostMethod(exchange, chain, request);        }			        return chain.filter(exchange);    }    /**     * get请求 校验参数     * @param exchange     * @param chain     * @param request     * @return     */    private Mono<Void> verifyGetMethod(ServerWebExchange exchange, GatewayFilterChain chain, ServerHttpRequest request) {	// get请求获取参数        Map<String, String> queryParamMap = request.getQueryParams().toSingleValueMap();			// 具体业务参数        String secretId = queryParamMap.get("secretId");        String secretKey = queryParamMap.get("secretKey");	// 校验参数逻辑        return verifyParams(exchange, chain, secretId, secretKey);    }    /**     * post请求 校验参数     * @param exchange     * @param chain     * @param request     * @return     */    private Mono<Void> verifyPostMethod(ServerWebExchange exchange, GatewayFilterChain chain, ServerHttpRequest request) {        try {            GatewayContext gatewayContext = (GatewayContext)exchange.getAttributes().get(GatewayContext.CACHE_GATEWAY_CONTEXT);            // get body from gatewayContext            String cacheBody = gatewayContext.getCacheBody();            Map map = new ObjectMapper().readValue(cacheBody, Map.class);	    // 具体业务参数            String secretId = String.valueOf(map.get("secretId"));            String secretKey = String.valueOf(map.get("secretKey"));           	    // 校验参数逻辑            return verifyParams(exchange, chain, secretId, secretKey);        } catch (Exception e){            log.error("解析body内容失败:{}", e);            // 403            return response(exchange, R.fail().enumCode(HttpCode.FORBIDDEN));        }    }    /**     * 校验参数     * @param exchange     * @param chain     * @param secretId     * @param secretKey     * @return     */    private Mono<Void> verifyParams(ServerWebExchange exchange, GatewayFilterChain chain, String secretId, String secretKey) {        // 校验失败,则返回相应提示	// return response(exchange, R.fail().enumCode(HttpCode.UNAUTHORIZED));        // todo	// 校验成功,则当前过滤器执行完毕        return chain.filter(exchange);    }    /**     * response 返回code     * @param exchange     * @param r     * @return     */    private Mono<Void> response(ServerWebExchange exchange, R r) {        ServerHttpResponse originalResponse = exchange.getResponse();        originalResponse.setStatusCode(HttpStatus.OK);        originalResponse.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);        try {            byte[] bytes = new ObjectMapper().writeValueAsBytes(r);            DataBuffer buffer = originalResponse.bufferFactory().wrap(bytes);            return originalResponse.writeWith(Flux.just(buffer));        } catch (JsonProcessingException e) {            e.printStackTrace();            return null;        }    }    @Override    public int getOrder() {        return FilterOrderConstant.getOrder(this.getClass().getName());    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发