当前位置:   article > 正文

beta-Sprintin the achievement of gateway

beta-Sprintin the achievement of gateway

一.Present main task

Developing a simple API interface

(1)Front end and back end separation

Developing a simple API interface Front end and back end separation is beneficial for promoting API independence between the front-end and back-end during development and maintenance. The front-end and back-end can be developed separately, simply communicating through defined API interfaces. This separation simplifies team collaboration, allowing front-end and back-end developers to focus on their respective fields.

(2)Beneficial for cross platform and cross language compatibility

APIs provide a standardized communication method that enables effective data exchange between different platforms and programming languages. This means that you can use different technology stacks to build the front-end and back-end, as long as they both understand and follow the same API specifications.

(3) Service based architecture

By dividing different functions into independent services, each service communicates with other services through APIs, making our project more flexible, scalable, and easy to maintain

(4) Mobile application development

APIs provide a standard way to communicate with mobile applications. Mobile applications can obtain data and perform operations by calling backend APIs, enabling developers to provide data to multiple platforms using a unified backend service.

(5)Our focus is on completing third-party integration

providing API interfaces to enable third-party developers to integrate your services or data, promoting the development of the ecosystem. This openness can drive innovation and make your services more widely used by other applications or systems.

二.Description of each member

NamediscriptiondifficultcostingTime
Du JiachengDevelop an easy-to-use SDK that cares about which interfaces to call and which parameters to pass as if it were your own codeNo difficultyone day
Peng BoHow should the API gateway be organized, such as in security to prevent attacks, in restrictions, open, can not be called at will. At the same time, the number of calls, billing, traffic protection, API access should be randomly countedNo difficultyone day
Wu GaoyuanHelp test the different functions of these API gatewaysThere will be some environment configuration issuesone day
Li YujieTo achieve release control, such as the launch of a new interface, for example, the first to allocate 20% traffic to the new street interface, the original old interface to allocate 80% traffic. With a weighted gateway, you can achieve 10 users, 8 to one address, 2 to another addressThink about how to combine this functionality with back-end limiting and permissions into a gateway blocking classone day
Cheng zhengyiWhat I have been doing in the past few days is for the front-end to send the user input request parameters and the ID to be tested to the backend user platform. Before calling, some debugging can be done, and the platform backend needs to call the simulated interface user interface based on the addressWhen testing a request for a mock interface, a direct request for a mock interface will result in an error, but a direct call to the back-end will result in an errorone day
Chen zhenHaving a deep understanding of AOP, the most common approach is to separate logs from business logic. AOP can be used to write logs before and after the execution of business logic, without affecting the already written business logic codeDue to the existence of a single project in the AOP aspect, each interface development requires writing a section. When considering how to reduce this complex taskone day
Li ZijunUnderstand the concept of AOP, understand the pointcut, notification, section, do a function, after each interface call the number of statistics plus 1The functional code is cumbersome and needs to be simplifiedone day
Chen YaoUnderstand the gateway and understand some of the problems that the gateway handles. To use microservices to implement routing, hoping to play the role of forwarding forwarding, such as interface A and interface B, the gateway will record these information, access parameters according to the address, and forward the corresponding request interfaceHow to save corresponding to our projectone day
Xie YanzheUnderstand the unified authentication function of the gateway, and think about the rights of many users, such as whether the user needs a key when invoking the interface, and whether the user needs to set a time to limit the interface timeHow should database tables be designed, and should new fields be addedone day
zhang HanlinDesign key encryption algorithm, consider a variety of encryption methods, such as symmetric encryption, asymmetric encryption, MD5 encryption. There are also signature generation algorithmsSome encryption algorithms have not yet been fully implemented.one day
Cai SiyuanAccording to the above gateway content, make a front-end UI control, so that it can display the parameters of the gateway call interface, but also can display the gateway call time and the url of the calling userNo difficultyone day
Lin ZehuiDraw the page where the gateway interface forwards or calls the gatewayNo difficultyone day
Bu ChenyuPropose some requirements that the gateway also needs, so as to better satisfy the userNo difficultyone day
Li HengMainly monitor the progress of our project, and collect our difficulties and suggestionsNo difficultyone day
Wang NingfeiWrite API corresponding interface documentation, such as interface request header, request parameters, interface function descriptionNo difficultyone day

3.Develop code and flow charts

(1)A dedicated client for the SDK

Here is a simple test to get the user name, and some other features will be added in the future

import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.yupi.yuapiclient.model.User;


import java.util.HashMap;
import java.util.Map;


import static com.yupi.yuapiclient.utils.SignUtils.getSign;

/**
 * 调用第三方接口的客户端
 */
public class YuApiClient {

    private static final String GATEWAY_POST="http://localhost:8090";

    private String accessKey;

    private String secretKey;

    public YuApiClient(String accessKey,String secretKey){
        this.accessKey=accessKey;
        this.secretKey=secretKey;
    }


    public String getName(String name){
          //可以单独传入http参数,这样参数就会自动做URL编码,拼接在URL中
        HashMap<String, Object> paraMap=new HashMap<>();
        paraMap.put("name",name);
        String result= HttpUtil.get(GATEWAY_POST+"/api/name/",paraMap);
        System.out.println(result);
        return result;
    }


    public String getNameByPost( String name){
        //可以单独传入http参数,这样参数就会自动做URL编码,拼接在URL中
        HashMap<String, Object> paraMap=new HashMap<>();
        paraMap.put("name",name);
        String result= HttpUtil.post(GATEWAY_POST+"/api/name/",paraMap);
        System.out.println(result);
        return result;

    }



    /**
     * API签名认证
     * @param body
     * @return
     */
    private Map<String,String> getHeaderMap(String body){
        Map<String,String> hashMaps=new HashMap<>();
        hashMaps.put("accessKey",accessKey);//密钥
        //密码不能给后端知道的
        // hashMaps.put("secretKey",secretKey);
        hashMaps.put("nonce", RandomUtil.randomNumbers(4)) ;//做一个随机数,在重放时,只执行一次
        hashMaps.put("body",body); //请求参数
        hashMaps.put("timestamp",String.valueOf(System.currentTimeMillis()/1000)); //时间戳
        hashMaps.put("sign",getSign(body, secretKey)); //md5加密签名
        return hashMaps;
    }

    /**
     * 如果得到参数是为JSON
     * @param user
     * @return
     */
    public String getUsername(User user){
       String json= JSONUtil.toJsonStr(user);
        HttpResponse  httpResponse=HttpRequest.post(GATEWAY_POST+"/api/name/json")
                .addHeaders(getHeaderMap(json)).body(json).execute(); //在发url时,也发了一个请求头,以便后端验证

        System.out.println(httpResponse.getStatus());
        String result=httpResponse.body();
        System.out.println(result);
        return result;



    }
}
  • 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

Configuration

@Configuration
@ConfigurationProperties("yuapi.client")
@Data
@ComponentScan
public class yuApiClientConfig {

    private String accessKey;

    private String secretKey;

    @Bean
    public YuApiClient yuApiClient(){
        return new YuApiClient(accessKey,secretKey);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  <dependency>
            <groupId>com.yupi</groupId>
            <artifactId>yuapi-client</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

(2)API Gateway forwarding interface configuration

server:
  port: 8090
spring:
  cloud:
    gateway:
      routes:
        - id: api_route
          uri: http://localhost:8123
          predicates:
            - Path=/api/{api_url}/**
#        - id: add_request_header_route
#          uri: http://localhost:8123
#          predicates:
#            - Path=/api/**
#          filters:
#            - AddRequestHeader=yupi, swagger
#            - AddRequestParameter=name, dog
    #     - id: after_route
    #      uri: https://www.codefather.cn/%E4%BC%99%E4%BC%B4%E5%8C%B9%E9%85%8D%E7%B3%BB%E7%BB%9F/#????
    #     predicates:
    #        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
    #       - id: path_route
    #        uri: https://codefather.cn/
    #        predicates:
    #          - Path=/red/**
logging:`在这里插入代码片`
  level:
    org:
      springframework:
        cloud:
          gateway: trace
  • 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

(3)Global configuration class

/**
 * 全局过滤
 */
@Slf4j
@Component
public class GloobalFilter implements GlobalFilter, Ordered {


    private static final List<String> IP_WHITE_LIST= Arrays.asList("127.0.0.1");
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("进入到此网关");
//        1.用户发送请求到API网关
        /*
        已在application.yml配置
         */
//        2.请求日志
         ServerHttpRequest request=  exchange.getRequest(); //exchange就是检测的路径
        log.info("请求唯一标识: "+request.getId());
        log.info("路径: "+request.getPath().value());
        log.info("请求方法: "+request.getMethod());
        log.info("请求参数: "+request.getQueryParams());
        log.info("请求来源地址1: "+request.getLocalAddress().getHostString());
        log.info("请求来源地址2: "+request.getRemoteAddress());
        ServerHttpResponse response=exchange.getResponse();//获取响应体
        String sourceAddress=String.valueOf(request.getLocalAddress().getHostString());
//        3.(黑白名单)
   if(!IP_WHITE_LIST.contains(sourceAddress)){ //判读路径是否是本机地址,如果不是,则拒绝请求访问
       response.setStatusCode(HttpStatus.FORBIDDEN);
       return response.setComplete();
   }

//        4.用户鉴权(判断ak,sk是否合法)
     HttpHeaders headers=request.getHeaders();
    String accessKey=headers.getFirst("accesskey");
    String nonce=headers.getFirst("nonce");
    String timestamp=headers.getFirst("timestamp");
    String sign=headers.getFirst("sign");
    String body=headers.getFirst("body");

    //todo 根据情况应该是从数据库查找是否已分配好的用户
        if(!accessKey.equals("yupi")){
            response.setStatusCode(HttpStatus.FORBIDDEN);
            return response.setComplete();
        }
        if(Long.parseLong(nonce)>10000){
            response.setStatusCode(HttpStatus.FORBIDDEN);
            return response.setComplete();
        }
        //当前时间和现在时间不能超过5分钟
        Long currentTime=System.currentTimeMillis()/1000;
         final Long FIVE_MINUTES=60*5L;
        if((currentTime-Long.parseLong(timestamp))>=FIVE_MINUTES){
            response.setStatusCode(HttpStatus.FORBIDDEN);
            return response.setComplete();
        }
        //todo 实际情况应该是从数据库取出secretkey
        String serverSign= SignUtils.getSign(body,"abcdefgh");
        if(!sign.equals(serverSign)){
            response.setStatusCode(HttpStatus.FORBIDDEN);
            return response.setComplete();
        }


//        5.请求的模拟接口是否存在
    //todo 从数据库中查询模拟接口是否存在,以及请求方法是否匹配(还可以校验请求参数)


//        6.请求转发,调用模拟接口
        Mono<Void> filter=chain.filter(exchange);
//        7.响应日志
       log.info("响应:"+response.getStatusCode());


//

       return testResponseLog(exchange, chain);


    }

    @Override
    public int getOrder() {
        return 0;
    }


    public Mono<Void> testResponseLog(ServerWebExchange exchange, GatewayFilterChain chain){
        log.info("进入响应日志阶段");
        try {
            ServerHttpResponse originalResponse = exchange.getResponse();
           //缓存数据
            DataBufferFactory bufferFactory = originalResponse.bufferFactory();
          //拿到响应码
            HttpStatus statusCode = originalResponse.getStatusCode();

            if(statusCode == HttpStatus.OK){

                //装饰:增强能力
                ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {

                    @Override
                    public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                        //log.info("body instanceof Flux: {}", (body instanceof Flux));
                        if (body instanceof Flux) {
                            Flux<? extends DataBuffer> fluxBody = Flux.from(body);
                            //往返回里写数据
                            return super.writeWith(fluxBody.map(dataBuffer -> {
                                //        8. todo 调用成功,接口调用次数+1

                                byte[] content = new byte[dataBuffer.readableByteCount()];
                                dataBuffer.read(content);
                                DataBufferUtils.release(dataBuffer);//释放掉内存
                                // 构建日志
                                StringBuilder sb2 = new StringBuilder(200);
                                sb2.append("<--- {} {} \n");
                                List<Object> rspArgs = new ArrayList<>();
                                rspArgs.add(originalResponse.getStatusCode());
                                //rspArgs.add(requestUrl);
                                String data = new String(content, StandardCharsets.UTF_8);//data
                                sb2.append(data);
                                log.info(sb2.toString(), rspArgs.toArray());//log.info("<-- {} {}\n", originalResponse.getStatusCode(), data);
                                return bufferFactory.wrap(content);
                            }));
                        } else {

                            //        9.调用失败,返回一个规范的错误码
                            log.error("<--- {} 响应code异常", getStatusCode());
                        }
                        return super.writeWith(body);
                    }
                };
                return chain.filter(exchange.mutate().response(decoratedResponse).build());
            }
            return chain.filter(exchange);//降级处理返回数据
        }catch (Exception e){
            log.error("网关处理响应错误" + e);
            return chain.filter(exchange);
        }

    }
    public Mono<Void> handleInvokeError(ServerHttpResponse response){
        response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
        return response.setComplete();
    }
}
  • 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

4测试

5小组照片

6 .Summaize the project

(1)Expected taskof the entire project

At this stage, we are mainly mobile applications, so we need to interact with each other through API gateways.And it is hoped that through the API gateway to achieve more non-functional requirements, such as protection interface, interception and so on
The problem:How does the database match up with the code

(2) the work that has been completed so far

The gateway implements the interception and forwarding functions

7.burn-up chart

8.Record the changes in the total amount of tasks

changesDescription
databaseHow to set many fields of the database, in order to interact with some permission functions, and need to import database packages in some separate gateway projects, will it be troublesome
How to call the functions of other projectsWe propose the following possible approaches, but have not yet tested them:Copy the code and dependencies, and of course configure the environment,HTTP request (provides an interface for other projects to use)RPC,Make a jar package of the public code and reference it to other projects (such as the client SDK of this API gateway).

9.Picture

module:
在这里插入图片描述

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号