SpringCloud GateWay網關無法返回信息數據與Expect: 100-continue

最近做支付項目從大的項目獨立出來所以專門搭建了一個網關。上網查了些資料都說SpringCloud GateWay性能比較好所以就搭建了,其中踩了不了坑,包括JWT權限驗證、限流等。但這些搭建都算比較容易網上已經有了很多教程。踩的最坑花時間最長的就是支付交易後,接收交易通知服務處理過後返回響應數據接收不到。下面做的僅做簡單模擬。

1.搭建一個簡單網關

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.gate</groupId>
    <artifactId>gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gateway</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR1</spring-cloud.version>
    </properties>



    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>27.1-jre</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

響應攔截,打印響應信息

package com.gate;

import lombok.extern.slf4j.Slf4j;
import org.omg.CORBA.PUBLIC_MEMBER;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpStatus;
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.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

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


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //獲取返貨response
        ServerHttpResponse originalResponse = exchange.getResponse();
        DataBufferFactory bufferFactory = originalResponse.bufferFactory();

        HttpStatus statusCode = originalResponse.getStatusCode();

        if (statusCode ==HttpStatus.OK){
            ServerHttpResponseDecorator decorator = new ServerHttpResponseDecorator(originalResponse){

                @Override
                public Mono<Void> writeWith(Publisher<? extends DataBuffer> body){
                    Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                    return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
                        DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
                        DataBuffer join = dataBufferFactory.join(dataBuffers);
                        byte[] content = new byte[join.readableByteCount()];
                        join.read(content);

                        DataBufferUtils.release(join);
                        String responseData = new String(content, StandardCharsets.UTF_8);
                        //responseData就是下游系統返回的內容,可以查看修改
                        log.info("響應內容:{}", responseData);
                        byte[] uppedContent = new String(responseData.getBytes(), Charset.forName("UTF-8")).getBytes();
                        return bufferFactory.wrap(uppedContent);

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

    @Override
    public int getOrder() {
        return -2;
    }
}

application.yml配置

server:
  port: 8080
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
        - id: add_request_parameter_route
          uri: lb://producer
          predicates:
            - Path=/producer/**
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

2.註冊中心比較簡單可以自己自行搭建

3.搭建一個服務提供者

@RestController
@RequestMapping("/producer")
public class TestController {

    @RequestMapping("/foo")
    public String foo(String foo) {
        return "hello "+foo+"!";
    }

    @PostMapping("/test")
    public Object test(@RequestParam Map<String,String> paramsMap){
        System.out.println(paramsMap);

        return paramsMap;
    }




}

下面用postMan請求網關。

服務接收到參數

 

網關接收到信息

好了,下面看下怎麼讓網關接收不到響應信息。

只需在請求頭中加入Expect: 100-continue 這個字段,postman會一直保持請求狀態,並且最終無響應參數返回。

原因:可以參考https://www.cnblogs.com/nangcr/p/informational-responses-status-code-100-in-http.html

我之前就是不知道交易通知中竟然傳了那麼坑的參數,研究了好久。

 

那麼怎麼解決在SpringCloud GateWay中將頭信息Expect去掉呢?

參考:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.3.RELEASE/single/spring-cloud-gateway.html#_removerequestheader_gatewayfilter_factory

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章