赞
踩
Developing a simple API interface
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.
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.
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
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.
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.
Name | discription | difficult | costingTime |
---|---|---|---|
Du Jiacheng | Develop an easy-to-use SDK that cares about which interfaces to call and which parameters to pass as if it were your own code | No difficulty | one day |
Peng Bo | How 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 counted | No difficulty | one day |
Wu Gaoyuan | Help test the different functions of these API gateways | There will be some environment configuration issues | one day |
Li Yujie | To 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 address | Think about how to combine this functionality with back-end limiting and permissions into a gateway blocking class | one day |
Cheng zhengyi | What 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 address | When 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 error | one day |
Chen zhen | Having 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 code | Due 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 task | one day |
Li Zijun | Understand the concept of AOP, understand the pointcut, notification, section, do a function, after each interface call the number of statistics plus 1 | The functional code is cumbersome and needs to be simplified | one day |
Chen Yao | Understand 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 interface | How to save corresponding to our project | one day |
Xie Yanzhe | Understand 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 time | How should database tables be designed, and should new fields be added | one day |
zhang Hanlin | Design key encryption algorithm, consider a variety of encryption methods, such as symmetric encryption, asymmetric encryption, MD5 encryption. There are also signature generation algorithms | Some encryption algorithms have not yet been fully implemented. | one day |
Cai Siyuan | According 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 user | No difficulty | one day |
Lin Zehui | Draw the page where the gateway interface forwards or calls the gateway | No difficulty | one day |
Bu Chenyu | Propose some requirements that the gateway also needs, so as to better satisfy the user | No difficulty | one day |
Li Heng | Mainly monitor the progress of our project, and collect our difficulties and suggestions | No difficulty | one day |
Wang Ningfei | Write API corresponding interface documentation, such as interface request header, request parameters, interface function description | No difficulty | one day |
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; } }
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); } }
<dependency>
<groupId>com.yupi</groupId>
<artifactId>yuapi-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
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
/** * 全局过滤 */ @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(); } }
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
The gateway implements the interception and forwarding functions
changes | Description |
---|---|
database | How 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 projects | We 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). |
module:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。