目录

Feign 声明式web服务客户端

feign 声明式web客户端使用

eurekaserver_changsha(注册中心)

eureka-client-food(服务提供者)

feign-client-cat(服务消费者)

浏览器访问微服务调用测试

Feign 请求与响应压缩 与 日志


Feign 声明式web服务客户端

spring-cloud-openfeign 官网:https://spring.io/projects/spring-cloud-openfeign

spring cloud 官方 2.1.x 文档:https://cloud.spring.io/spring-cloud-openfeign/2.1.x/single/spring-cloud-openfeign.html

feign Github 开源地址:https://github.com/OpenFeign/feign

1、feign 是一个声明式 Web 服务客户端/http 客户端,它使编写 Web 服务客户端更加容易,要使用 feign,请创建一个接口并对其进行注释。它具有可插拔的注解支持,包括外部注解和 JAX-RS 注解。Feign 还支持可插拔的编码器和解码器。

2、Spring Cloud 增加了对 Spring MVC 注解的支持,并支持使用 Spring Web 中默认使用的 HttpMessageConverters,Spring Cloud 集成了 Ribbon 和 Eureka,在使用 Feign 时提供一个负载均衡的 http 客户端。

3、虽然直接使用 org.springframework.web.client.RestTemplate 也可以实现微服务之间的 http 调用,但是 feign 作为一个独立的库,更具有优势,它使得调用远程微服务的 API 就如同调用自己本地的 API 一样。

4、How to Include Feign?按着官网文档介绍,使用 feign 很简单,分为如下几步:

1)服务请求/调用/消费方在 pom.xml 文件中导入 feign 依赖:

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

2)服务请求/调用/消费方在启动类上加上 @org.springframework.cloud.openfeign.EnableFeignClients 注解开启 feignClient 客户端:

@SpringBootApplication
@EnableFeignClients
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

3)服务请求/调用/消费方创建一个接口,@FeignClient 表示此接口为 feign 客户端,"stores" 为服务提供者的微服务名称,可以从注册中心看到,接口中的方法就是服务提供者 Cotroller 层的方法。

其中 @RequestMapping 请求方式必须与服务提供者提供的方式一致,value 是请求路径,如果对方设置了应用上下文,则 value 中也要加上,方法名称可以自定义,不过建议与服务提供者一致。

@FeignClient("stores")
public interface StoreClient {@RequestMapping(method = RequestMethod.GET, value = "/stores")List<Store> getStores();@RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")Store update(@PathVariable("storeId") Long storeId, Store store);
}

4)然后服务请求/调用/消费方可以在自己的 Controller 中调用上面接口中的方法,表面上好像调用自己的 API,实际上会通过微服务名称和路径调用远程微服务接口。

官网文档:https://cloud.spring.io/spring-cloud-openfeign/2.1.x/single/spring-cloud-openfeign.html#netflix-feign-starter

feign 声明式web客户端使用

1、使用非常简单,开发环境为:Java JDK 1.8 + Spring Boot 2.1.3 + Spring Cloud Greenwich.SR1 + IDEA 2018。

2、准备三个微服务应用:eurekaserver_changsha 应用作 eureka 服务端,用于服务注册;eureka-client-food 应用提供服务;feign-client-cat 应用作为服务请求者,请求 eureka-client-food 提供的服务(接口)

3、操作流程:用户从浏览器访问 feign-client-cat 、feign-client-cat 应用内部调用 eureka-client-food 微服务,然后返回数据。

eurekaserver_changsha(注册中心)

1、pom.xml 文件核心内容如下(详细源码地址:https://github.com/wangmaoxiong/feign_first):

...
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.3.RELEASE</version><relativePath/> <!-- lookup parent from repository -->
</parent>
...
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

2、全局配置文件内容如下(详细源码地址:https://github.com/wangmaoxiong/feign_first):

server:port: 9393
eureka:server:enable-self-preservation: false #关闭自我保护机制eviction-interval-timer-in-ms: 60000 #驱逐计时器扫描失效服务间隔时间。(单位毫秒,默认 60*1000)instance:hostname: localhostclient:register-with-eureka: false   #禁用自己向自己注册fetch-registry: false   #不同步其他的 Eureka Server节点的数据service-url:  #Eureka Client 与 Eureka Server 交互的地址default-zone: http://${eureka.instance.hostname}:${server.port}/eureka/

3、启动类上添加 @EnableEurekaServer:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/*** @EnableEurekaServer:开启 eureka 服务*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaserverChangshaApplication {public static void main(String[] args) {SpringApplication.run(EurekaserverChangshaApplication.class, args);}
}

注册中心提供服务注册,内容不多。

eureka-client-food(服务提供者)

1、pom.xml 文件核心内容如下(详细源码地址:https://github.com/wangmaoxiong/feign_first):

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.3.RELEASE</version><relativePath/> <!-- lookup parent from repository -->
</parent>
...
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
...

2、全局配置文件内容如下(详细源码地址:https://github.com/wangmaoxiong/feign_first):

server:port: 9395  #服务器端口servlet:context-path: /food   #应用访问上下文
spring:application:name: eureka-client-food  #微服务名称
eureka:client:service-url:defaultZone: http://localhost:9393/eureka/ #eureka 服务器地址instance:prefer-ip-address: true # IP 地址代替主机名注册instance-id: changSha-food # 微服务实例id名称

3、服务提供者提供的服务就是 http 访问的接口,所以创建一个 Controller 层,提供访问接口,其中提供了不同参数的访问方式,以达到基本满足日常开发的需要:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import wmx.com.eurekaclient_food.pojo.Person;
import java.io.IOException;
import java.time.LocalDateTime;
/*** 菜谱** @author wangmaoxiong*/
@RestController
public class Cuisine {private static final Logger logger = LoggerFactory.getLogger(Cuisine.class);/*** 获取湘菜菜谱数据。访问地址:http://localhost:9395/food/getHunanCuisine?uuid=98389uou8309adko990** @return*/@GetMapping("getHunanCuisine")public String getHunanCuisine(String uuid) {logger.info("获取湖南菜谱,uuid = {}", uuid);JsonNodeFactory nodeFactory = JsonNodeFactory.instance;//以 json 格式返回ArrayNode arrayNode = nodeFactory.arrayNode().add("辣椒炒肉").add("剁椒鱼头").add("蚂蚁上树").add(StringUtils.trimToNull(uuid));return arrayNode.toString();}/*** 根据 id 删除:http://localhost:9395/food/deleteDataById?id=980890** @param id* @return*/@GetMapping("deleteDataById")public String deleteDataById(@RequestParam(value = "id") Integer id) {logger.info("根据 id 删除,id = {}", id);JsonNodeFactory nodeFactory = JsonNodeFactory.instance;ObjectNode objectNode = nodeFactory.objectNode();//以 json 格式返回objectNode.put("id", id);objectNode.put("code", 200);objectNode.put("message", "delete success");return objectNode.toString();}/*** 更新:http://localhost:9395/food/updateData/889uuo65eud99?data=name_zhangsan,age_33** @param uid  :使用路径变量* @param data :使用普通的请求参数* @return*/@RequestMapping(value = "updateData/{uid}", method = RequestMethod.GET)public String updateData(@PathVariable("uid") String uid, String data) {logger.info("更新数据,uid = {}, data = {}", uid, data);JsonNodeFactory nodeFactory = JsonNodeFactory.instance;ObjectNode objectNode = nodeFactory.objectNode(); //以 json 格式返回objectNode.put("code", 200);objectNode.put("message", "更新成功");objectNode.put("uid", uid);objectNode.put("data", data);return objectNode.toString();}/*** 保存数据:http://localhost:9395/food/saveData?type=saveing** @param jsonData :使用请求正文(json 格式)传入,数据在请求体中,如:{"id":9527,"name":"华安","order":100000},页面必须传入* @param type     :使用普通的 key-value 格式传入,数据在请求透中* @return*/@PostMapping("saveData")public String saveData(@RequestBody String jsonData, @RequestParam String type) {logger.info("保存数据,jsonData = {}, type = {}", jsonData, type);JsonNodeFactory nodeFactory = JsonNodeFactory.instance;ObjectNode objectNode = nodeFactory.objectNode();//以 json 格式返回try {objectNode.put("code", 200);objectNode.put("message", "保存成功");objectNode.put("type", type);ObjectMapper objectMapper = new ObjectMapper();JsonNode jsonNode = objectMapper.readTree(jsonData);objectNode.set("jsonDta", jsonNode);} catch (IOException e) {e.printStackTrace();}return objectNode.toString();}/*** 测试 get 方式复杂对象调用:http://localhost:9395/food/updatePerson?pid=100&pname=张三&age=33** @param person* @return*/@GetMapping("updatePerson")public Person updatePerson(Person person) {logger.info("更新数据 person = {}", person);person.setBirthday(LocalDateTime.now());return person;}/*** 测试 post 方式复杂对象调用:http://localhost:9395/food/updatePerson2?pid=100&pname=张三&age=33* 1、对于复杂对象,不建议使用 @RequestBody 在请求体中传递数据,因为 feignClient 客户端调用时会很难处理* 2、如果非得要使用 @RequestBody ,则建议使用 String 类型,而不是复杂对象* 3、也可以如下所示,使用请求头传递参数,这样 feignClient 客户端可以将复杂对象拆成属性调用** @param person* @return*/@PostMapping("updatePerson2")public Person updatePerson2(Person person) {logger.info("更新数据(post) person = {}", person);person.setBirthday(LocalDateTime.now());return person;}
}

feign-client-cat(服务消费者)

1、pom.xml 文件核心内容如下(详细源码地址:https://github.com/wangmaoxiong/feign_first):

<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.3.RELEASE</version><relativePath/> <!-- lookup parent from repository -->
</parent>
...
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
...

2、全局配置文件内容如下(详细源码地址:https://github.com/wangmaoxiong/feign_first):

server:port: 9394    #服务器端口servlet:context-path: /cat  #应用访问上下文
spring:application:name: feign-client-cat  #微服务名称
eureka:client:service-url:defaultZone: http://localhost:9393/eureka/ #eureka 服务器地址instance:prefer-ip-address: true # IP 地址代替主机名注册instance-id: feign-cat # 微服务实例id名称feign:name:food: eureka-client-food #服务提供方的服务名称,自定义配置。

3、启动类代码如下:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/*** @EnableFeignClients:开启 feign 客户端* @EnableEurekaClient:开启 eureka 客户端,可以不写,默认就是开启的*/
@SpringBootApplication
@EnableFeignClients
@EnableEurekaClient
public class FeignClientCatApplication {public static void main(String[] args) {SpringApplication.run(FeignClientCatApplication.class, args);}
}

4、提供 feign 客户端接口如下:

1)@FeignClient 注解的 vaule 和 name 其实是一个属性,互相使用了别名,完全等价。值为服务提供方的服务名称。

2)@FeignClient(name = "${feign.name.food}"):推荐方式,服务提供方的服务名称从配置文件读取。

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import wmx.com.feign_client_cat.pojo.Person;
import java.time.LocalDateTime;
/*** 1、@FeignClient :声明接口为 feign 客户端,value 值为被请求的微服务名称(注册中心可以看到,配置文件中的spring.application.name属性值),* value 可以省略如 @FeignClient("eureka-client-food")。推荐方式:@FeignClient(name = "${feign.name.food}")* 2、@FeignClient 接口中的方法名称可以自定义,但建议保持与对方一致,请求方式必须一致,请求路径记得带上服务提供方上下文路径(如果有的话)* 有些细节需要注意,下面注释中有说明*/
@FeignClient(value = "eureka-client-food")
public interface FoodFeignClient {/*** 获取湘菜菜谱数据* 1、"food" 是被请求应用的上下文件路径,一并写在方法上* 2、@GetMapping 也可以拆开写成:@RequestMapping(value = "food/getHunanCuisine", method = RequestMethod.GET)* 3、参数为字符串时,如果没加 @RequestParam("uuid") 请求参数注解,则请求时会抛异常如下:* feign.FeignException: status 405/404 reading FoodFeignClient#getHunanCuisine(String)* @return* @GetMapping("getHunanCuisine")*/@GetMapping("food/getHunanCuisine")public String getHunanCuisine(@RequestParam("uuid") String uuid);/*** 根据 id 删除* 1、@RequestMapping 也可以换成 @GetMapping("food/deleteDataById")* 2、经过实测参数为整形时,@RequestParam("id") 此时可加可不加,但都建议加上* @param id* @return*/@RequestMapping(value = "food/deleteDataById", method = RequestMethod.GET)public String deleteDataById(@RequestParam("id") Integer id);/*** 更新* 1、@PathVariable("uid") 注解可以不写 value 属性* 2、再次提醒:对于 String 参数,服务提供者方法上有没有加 @RequestParam,feignClient 客户端都需要加上,否则调用失败,抛异常:* feign.FeignException: status 405 reading FoodFeignClient#updateData(String,String)* @param uid  :使用路径变量* @param data :使用普通的请求参数* @return*/@GetMapping(value = "food/updateData/{uid}")public String updateData(@PathVariable("uid") String uid, @RequestParam String data);/*** 保存数据,post 请求。再次提醒 food 是服务提供者应用上下文件路径* @return*/@PostMapping("food/saveData")public String saveData(@RequestBody String jsonData, @RequestParam String type);/*** 测试复杂对象调用* 1、对于 get 请求,参数为复杂对象时,feignClient 中如果直接使用 public Person updatePerson(Person person); 会抛异常:* feign.FeignException: status 404 reading FoodFeignClient#updatePerson(Person)* 2、抛异常的原因是对于get方式复杂对象传递时,虽然已经指明了是 get 方式,但是 feign 还是会以 post 方式传递,导致调用失败* 3、解决方式1:可以和服务提供者协商,转换成 String 的方式进行传递;解决方式2:将复杂对象(Pojo) 拆成简单的属性,如下所示* @return*/@GetMapping("food/updatePerson")public Person updatePerson(@RequestParam Integer pid,@RequestParam String pname,@RequestParam Integer age,@RequestParam LocalDateTime birthday);/*** 测试 post 方式复杂对象调用* 1、与 get 方式差不多,当服务提供者使用 updatePerson2(Person person) 时,feign 客户端不能这么直接传递* 虽然 post 方式这样直传不会报错,但是对方接收不到数据,所以仍然只能拆成简单的属性进行传递* 2、如果对方要求的是 @RequestBody ,则此时这样写会直接抛异常,推荐解决方式是使用 String 类型传递* @return*/@PostMapping("food/updatePerson2")public Person updatePerson2(@RequestParam Integer pid,@RequestParam String pname,@RequestParam Integer age,@RequestParam LocalDateTime birthday);
}

5、@FeignClient 客户端接口中的方法请求方式要求与服务提供者一致,然而服务消费者自己控制层的调用方式是不受约束的,可以自己随意设置,控制层调用代码如下:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import wmx.com.feign_client_cat.feignClient.FoodFeignClient;
import wmx.com.feign_client_cat.pojo.Person;
import javax.annotation.Resource;
@RestController
public class CatController {private static final Logger logger = LoggerFactory.getLogger(CatController.class);//注入 feign 客户端实例。有了 feign 之后,调用远程微服务就如同调用自己本地的方法一样简单//@FeignClient 客户端接口中的方法请求方式要求与服务提供者一致,然而服务消费者自己控制层的调用方式是不受约束的@Resourceprivate FoodFeignClient foodFeignClient;/*** 查询湖南菜谱:http://localhost:9394/cat/getHunanCuisine?uuid=77884934euei000pp* @param uuid* @return*/@GetMapping("getHunanCuisine")public String getHunanCuisine(String uuid) {logger.info("查询湖南菜谱,uuid = {}", uuid);String result = this.foodFeignClient.getHunanCuisine(uuid);return result;}/*** 根据 id 删除:http://localhost:9394/cat/deleteDataById?id=980890* @param id* @return*/@GetMapping("deleteDataById")public String deleteDataById(@RequestParam(value = "id") Integer id) {logger.info("根据 id 删除,id = {}", id);String result = this.foodFeignClient.deleteDataById(id);return result;}/*** 更新:http://localhost:9394/cat/updateData/889uuo65eud99?data=name_zhangsan,age_33* @param uid  :使用路径变量* @param data :使用普通的请求参数* @return*/@RequestMapping(value = "updateData/{uid}", method = RequestMethod.GET)public String updateData(@PathVariable("uid") String uid, String data) {logger.info("更新数据,uid = {}, data = {}", uid, data);String result = this.foodFeignClient.updateData(uid, data);return result;}/*** 保存数据:http://localhost:9394/cat/saveData?type=saveing* @param jsonData :使用请求正文(json 格式)传入,数据在请求体中,如:{"id":9527,"name":"华安","order":100011}* @param type     :使用普通的 key-value 格式传入,数据在请求透中* @return*/@PostMapping("saveData")public String saveData(@RequestBody String jsonData, @RequestParam String type) {logger.info("保存数据,jsonData = {}, type = {}", jsonData, type);String result = this.foodFeignClient.saveData(jsonData, type);return result;}/*** 测试 get 方式复杂对象调用:http://localhost:9394/cat/updatePerson?pid=100&pname=张三&age=33* @param person* @return*/@GetMapping("updatePerson")public Person updatePerson(Person person) {logger.info("updatePerson(get) person = {}", person);return this.foodFeignClient.updatePerson(person.getPid(),person.getPname(),person.getAge(),person.getBirthday());}/*** 测试 post 方式复杂对象调用:http://localhost:9394/cat/updatePerson2* 1、@RequestBody:表示参数通过请求体传递,且为 json 格式,所以前端必须设置请求类型:Content-Type: application/json* @param person :{"pid":9334,"pname":"华雄","age":35}* @return*/public Person updatePerson2(@RequestBody Person person) {logger.info("updatePerson(post) person = {}", person);return this.foodFeignClient.updatePerson2(person.getPid(),person.getPname(),person.getAge(),person.getBirthday());}
}

详细源码地址:https://github.com/wangmaoxiong/feign_first

浏览器访问微服务调用测试

1、顺序启动 eureka 注册中心、服务提供者、服务消费者,然后从浏览器请求 feign-client-cat,如果它能从 eureka-client-food(服务提供者)获取数据并返回,则说明成功。

2、因为有 post 请求,所以在 firefox 浏览器上安装使用 https://addons.mozilla.org/zh-CN/firefox/addon/restclient/ 插件进行访问测试:

Feign 请求与响应压缩 与 日志

Feign 请求与响应压缩

1、Feign request/response compression:可以为 feign 请求或响应 使用 gzip 压缩,压缩设置与为 web 服务器的设置类似,允许选择压缩媒体类型和最小请求阈值长度。哪边使用 feign 就配置在哪边。

feign.compression.request.enabled=true      #开启 feign 请求压缩,默认 false
feign.compression.response.enabled=true     #开启 feign 响应压缩,默认 false
feign.compression.request.mime-types=text/xml,application/xml,application/json      #设置 feign 请求压缩类型
feign.compression.request.min-request-size=2048     #开启 feign 请求压缩阈值,超过此值才进行压缩,默认 2048

Feign 日志记录

1、Feign logging:Feign 日志默认是不开启的,可以通过配置进行开启,如下所示,logging.level 表示日志级别,后面跟着 feign 客户端接口的完整类名,或者它的包名,日志记录只响应 debug 级别,所以值只能是 debug。

logging:level:wmx.com.feign_client_cat.feignClient.FoodFeignClient: debug

2、上面的配置开启之后表示 feign 可以记录日志了,但是具体怎么记录,还需要在配置类(@Configuration)中进行指定记录级别:

NONE:无日志记录(默认)

BASIC:基本,只记录请求方法和 url 以及响应状态代码和执行时间。

HEADERS: 头,记录基本信息以及请求和响应头。

FULL: 完整,记录请求和响应的头、正文和元数据。

3、例下面将 logger.level 设置为 full 级别:

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SysConfig {@BeanLogger.Level feignLoggerLevel() {return Logger.Level.FULL;}
}

4、当再次访问 feign-client-cat 微服务,它内部调用 eureka-client-food 时,控制台打印日志记录如下:

2019-11-04 17:35:36.768 DEBUG 8912 --- [nio-9394-exec-1] w.c.f.feignClient.FoodFeignClient        : [FoodFeignClient#updateData] <--- HTTP/1.1 200 (268ms)
2019-11-04 17:35:36.768 DEBUG 8912 --- [nio-9394-exec-1] w.c.f.feignClient.FoodFeignClient        : [FoodFeignClient#updateData] content-length: 89
2019-11-04 17:35:36.768 DEBUG 8912 --- [nio-9394-exec-1] w.c.f.feignClient.FoodFeignClient        : [FoodFeignClient#updateData] content-type: text/plain;charset=UTF-8
2019-11-04 17:35:36.768 DEBUG 8912 --- [nio-9394-exec-1] w.c.f.feignClient.FoodFeignClient        : [FoodFeignClient#updateData] date: Mon, 04 Nov 2019 09:35:36 GMT
2019-11-04 17:35:36.768 DEBUG 8912 --- [nio-9394-exec-1] w.c.f.feignClient.FoodFeignClient        : [FoodFeignClient#updateData]
2019-11-04 17:35:36.770 DEBUG 8912 --- [nio-9394-exec-1] w.c.f.feignClient.FoodFeignClient        : [FoodFeignClient#updateData] {"code":200,"message":"更新成功","uid":"889uuo65eud99","data":"name_zhangsan,age_33"}
2019-11-04 17:35:36.770 DEBUG 8912 --- [nio-9394-exec-1] w.c.f.feignClient.FoodFeignClient        : [FoodFeignClient#updateData] <--- END HTTP (89-byte body)

Feign 简介与使用入门,请求、响应压缩,日志记录相关推荐

  1. spring-boot使用springAOP对接口请求、异常、响应进行日志记录

    spring-boot使用springAOP对接口请求.异常.响应进行日志记录 日志切面类LogAspect 请求control异常全局监控 日志切面类LogAspect /*** @Author: ...

  2. 用户请求接口信息日志记录

    用户请求接口信息日志记录 这样可以详细了解到用户的操作记录更加快捷方便的统计以及排错 思路 1,定义一个注解 2,日志AOP切面类,把自定义的注解作为切点,当系统执行某一个添加了自定义注解的方法时,A ...

  3. asp.net core mvc接口,请求响应统一日志管理

    如何为api所有的请求和响应做一个统一的日志记录 1.创建日志类 public class RequestResponseLog {public string Url { get; set; }pub ...

  4. springboot html压缩,springboot 请求响应压缩

    官方文档原文:[https://docs.spring.io/spring-boot/docs/2.1.5.RELEASE/reference/htmlsingle/\#how-to-enable-h ...

  5. python中的logging记录日志_[ Python入门教程 ] Python中日志记录模块logging使用实例...

    python中的logging模块用于记录日志.用户可以根据程序实现需要自定义日志输出位置.日志级别以及日志格式. 将日志内容输出到屏幕 一个最简单的logging模块使用样例,直接打印显示日志内容到 ...

  6. .Net Core HttpClient处理响应压缩

    前言 在上篇文章[ASP.NET Core中的响应压缩]中我们谈到了在ASP.NET Core服务端处理关于响应压缩的请求,服务端的主要工作就是根据Content-Encoding头信息判断采用哪种方 ...

  7. nginx log记录请求响应日志及日志分割

    之前部署了quic的集群在aws,在测试的时候发现在大报文的情形下HTTP3的请求耗时比较不稳定,并且耗时比普通的HTTP2要大很多,就想看看请求的具体耗时有多少 请求响应日志记录 我的quic集群是 ...

  8. Ajax→异步的JavaScript和XML、HTTP请求响应、Ajax简介同步异步、XMLHttpRequest类的方法及属性、原生Ajax、Koa实现Ajax、接口文档、浏览器同源策略、反向代理

    浏览器服务器 HTTP请求响应 数据库后端语言 Ajax简介同步异步 Koa前端框架 XMLHttpRequest类的方法及属性 原生Ajax Koa实现Ajax JSON DOM 接口文档 浏览器同 ...

  9. “一切都是消息”--iMSF(即时消息服务框架)之【请求-响应】模式(点对点)...

    MSF的名字是 Message Service Framework 的简称,由于目前框架主要功能在于处理即时(immediately)消息,所以iMSF就是 immediately Message S ...

  10. java 请求响应_java http接口请求响应 request response

    接口类: 1 package org.sunshine.dcda.epg.wechat.controller.niao; 2 3 import javax.servlet.http.HttpServl ...

最新文章

  1. 从微服务到 Serverless | 开源只是开始,终态远没有到来
  2. 建站零基础入门:手把手教你如何自助建站
  3. android 微信 语音转文字,微信语音转文字功能
  4. linux下游戏手柄测试程序
  5. 【爬虫】9行python下载王者荣耀所有英雄的高清壁纸(附代码和图片下载)
  6. 表连接on 和where的区别
  7. 如何使用burpsuite对网站进行暴力破解?
  8. Qt入门视频教程地址分享
  9. STS配置Gradle
  10. 乔姆斯基生成语法_乔姆斯基与生成语法重点分析.ppt
  11. matlab imfill 大小,Python相当于Matlab函数’imfill’的灰度?
  12. 应收账款的清帐和对账
  13. 【FPGA】:MicroBlaze的使用
  14. 中国生物科技公司【Advanced Biomed】申请纳斯达克IPO上市
  15. 阿里云启动教育脱贫计划,在贵州三年免费培训8000人
  16. 如何在本机执行 pyscript (在网页中执行python)
  17. 什么pdf转Word转换器可以批量转换
  18. 【Hive】报错FAILED: SemanticExceptionFailed to breakup Windowing invocations into Groups.
  19. Qt基础-QString字母大小写转换
  20. 开源大佬从谷歌离职,要去更小的企业寻求变革

热门文章

  1. 欧几里德算法(求最大公约数和最小公倍数)
  2. mysql分组取每组前几条记录_[转] mysql分组取每组前几条记要(排名)
  3. 拓端tecdat|R语言ggmap空间可视化机动车碰撞–街道地图热力图
  4. 快速排序_two-powinters思想
  5. java 绘制动态波形图6,折线图波形图绘制(动态绘制,实时变化)
  6. pandas聚合group函数
  7. re.sub对多处字符串进行替换
  8. 一个不到300行的C语言打飞机游戏
  9. tensorflow:卷积函数----tf.nn.conv2d
  10. caffe常用小工具