当前位置: 首页 > news >正文

OpenFeign 入门与实战:快速搭建 Spring Cloud 微服务客户端

1. 前言

随着微服务架构的流行,服务之间的通信变得越来越重要。Spring Cloud 提供了一系列工具来帮助开发者构建分布式系统,其中 OpenFeign 是一个轻量级的 HTTP 客户端,它简化了 Web 服务客户端的开发。本文将介绍如何在 Spring Cloud 应用中使用 OpenFeign 来进行服务间的调用,并解决一些常见的配置问题。

2. 什么是 OpenFeign?

OpenFeign 是 Spring Cloud 的一部分,它是一个声明式的 Web 服务客户端。通过使用 OpenFeign,开发者可以以声明的方式编写 Web 服务客户端接口,而不需要创建模板化的 HTTP 请求。Feign 内置了 Ribbon,用于实现客户端负载均衡,使得调用服务注册中心中的服务变得更加容易。

官方地址:https://github.com/OpenFeign/feign

本篇文章示例代码:https://github.com/kerrsixy/cloud-demo

3. 快速入门

以调用user-service模块的 /user/{id} 接口为例。

 3.1 调用端引入依赖

在order-service服务的pom文件中引入feign的依赖:

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

3.2 调用端添加注解

在order-service的启动类添加注解开启Feign的功能:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;@EnableFeignClients
@SpringBootApplication
public class OrderServiceApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class, args);}
}

3.3 编写Feign的客户端 

import com.zjp.orderservice.entity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(name = "user-service")
public interface UserClient {@GetMapping("/user/{id}")User getUser(@PathVariable("id") Long id);
}

如果该类里都是以/user开头的可以改为:

import com.zjp.orderservice.entity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(name = "user-service", path = "/user")
public interface UserClient {@GetMapping("/{id}")User getUser(@PathVariable("id") Long id);
}

如果没有配置中心或配置中心有多个同名服务需要指定url,则需要额外配置url:

import com.zjp.orderservice.entity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(name = "user-service", url = "http://localhost:8080", path = "/user")
public interface UserClient {@GetMapping("/{id}")User getUser(@PathVariable("id") Long id);
}

这个客户端主要是基于SpringMVC的注解来声明远程调用的信息,比如:

  • 服务名称:user-service
  • 请求方式:GET
  • 请求路径:/user/{id}
  • 请求参数:Long id
  • 返回值类型:User

这样,Feign就可以帮助我们发送http请求。

注意:

  • 如果没有指定url,则name要写为服务名。
  • 如果指定了url,则name无论起什么名字都行,但是不能为null。

3.4. 测试 

import com.zjp.orderservice.entity.User;
import com.zjp.feginservice.client.UserClient;
import com.zjp.orderservice.entity.Order;
import com.zjp.orderservice.mapper.OrderMapper;
import com.zjp.orderservice.service.OrderService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;@Service
public class OrderServiceImpl implements OrderService {@Autowiredprivate UserClient userClient;@Overridepublic User getOrderById(Long id) {User user = userClient.getUser(id);return user;}
}

3.5. 总结

使用Feign的步骤:

  1. 引入依赖
  2. 添加@EnableFeignClients注解
  3. 编写FeignClient接口
  4. 使用FeignClient中定义的方法代替RestTemplate

4. 自定义配置

Feign可以支持很多的自定义配置,如下表所示:

类型

作用

说明

feign.Logger.Level

修改日志级别

包含四种不同的级别:NONE、BASIC、HEADERS、FULL

feign.codec.Decoder

响应结果的解析器

http远程调用的结果做解析,例如解析json字符串为java对象

feign.codec.Encoder

请求参数编码

将请求参数编码,便于通过http请求发送

feign. Contract

支持的注解格式

默认是SpringMVC的注解,原生注解:GitHub - OpenFeign/feign: Feign makes writing java http clients easier

feign. Retryer

失败重试机制

请求失败的重试机制,默认是没有,不过会使用Ribbon的重试

 一般情况下,默认值就能满足我们使用,如果要自定义时,只需要创建自定义的@Bean覆盖默认Bean即可。

下面以日志为例来演示如何自定义配置。

4.1 配置文件方式

1. 针对单个服务:

feign:  client:config: user-service: # 针对某个微服务的配置logger-level: FULL #  日志级别

2. 针对所有服务:

feign:  client:config: default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置logger-level: FULL #  日志级别

日志的级别分为四种:

  • NONE:不记录任何日志信息,这是默认值。
  • BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
  • HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
  • FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。

4.2. Java代码方式

也可以基于Java代码来修改日志级别,先声明一个类,然后声明一个Logger.Level的对象:

import feign.Logger;
import org.springframework.context.annotation.Bean;public class DefaultFeignConfiguration {@Beanpublic Logger.Level feignLogLevel() {return Logger.Level.BASIC; // 日志级别为BASIC}
}

如果要全局生效,将其放到启动类的@EnableFeignClients这个注解中,例如:

import com.zjp.orderservice.config.DefaultFeignConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
@SpringBootApplication
public class OrderServiceApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class, args);}
}

如果是局部生效,则把它放到对应的@FeignClient这个注解中,例如:

import com.zjp.orderservice.entity.User;
import com.zjp.orderservice.config.DefaultFeignConfiguration;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(name = "user-service",configuration = DefaultFeignConfiguration.class)
public interface UserClient {@GetMapping("/user/{id}")User getUser(@PathVariable("id") Long id);
}

注意:

需要将feign包下的日志级别设置为DEBUG,feign的日志才能在控制台输出,例如:

logging:level:com.zjp.orderservice.client: DEBUG

5. Feign的原理

6. Feign使用优化

6.1 http连接池

Feign底层发起http请求,依赖于其它的框架。其底层客户端实现包括:

  • URLConnection:默认实现,不支持连接池
  • Apache HttpClient :支持连接池
  • OKHttp:支持连接池

因此提高Feign的性能主要手段就是使用连接池代替默认的URLConnection。

这里我们用Apache的HttpClient来演示。

1. 引入依赖

在order-service的pom文件中引入Apache的HttpClient依赖:

<dependency><groupId>io.github.openfeign</groupId><artifactId>feign-httpclient</artifactId>
</dependency>

2. 配置连接池

在order-service的application.yml中添加配置:

feign:httpclient:enabled: true # 开启feign对HttpClient的支持max-connections: 200 # 最大的连接数max-connections-per-route: 50 # 每个路径的最大连接数

3. 校验是否配置成功

在FeignClientFactoryBean中的loadBalance方法中打断点:

Debug方式启动order-service服务,可以看到这里的client,底层就是Apache HttpClient:

6.2 feign超时

 Feign的底层用的是Ribbon或者LoadBalancer,我们可以手动设置超时时间。

 可以针对单个服务:

feign:client:config:user-service:connect-timeout: 5000 # 请求连接的超时时间read-timeout: 5000 # 请求响应的超时时间

 可以针对所有服务:

feign:client:config:default:connect-timeout: 5000 # 请求连接的超时时间read-timeout: 5000 # 请求响应的超时时间

 6.3 总结

Feign的优化:

1. 日志级别尽量用basic

2. 使用HttpClient或OKHttp代替URLConnection

        1)引入feign-httpClient依赖

        2)配置文件开启httpClient功能,设置连接池参数

3. 修改 OpenFeign 的超时时间,让 OpenFeign 能够正确的处理业务。

7. 最佳实践

在项目开发过程中可以发现,Feign的客户端与服务提供者的controller代码非常相似:

feign客户端:

@FeignClient(name = "user-service")
public interface UserClient {@GetMapping("/user/{id}")User getUser(@PathVariable("id") Long id);
}

服务提供者:

@GetMapping("/user/{id}")
public User getUser(@PathVariable("id") Long id) {return userService.getUserById(id);
}

有没有一种办法简化这种重复的代码编写呢?

7.1 继承方式(不推荐)

  1. 定义一个API接口,利用定义方法,并基于SpringMVC注解做声明。

  2. Feign客户端和Controller都集成改接口

优点:

  • 代码简单
  • 实现了代码的共享

缺点:

  • 服务提供方、服务消费方紧耦合
  •  参数列表中的注解映射并不会继承,因此Controller中必须再次声明方法、参数列表、注解

7.2 抽取方式

将Feign的Client抽取为独立模块,并且把接口有关的实体类、默认的Feign配置都放到这个模块中,提供给所有消费者使用。

例如,将UserClient、User、Feign的默认配置都抽取到一个feign-api包中,所有微服务引用该依赖包,即可直接使用。

7.2.1. 抽取

1. 创建新moudle

2. 在fegin-service中然后引入feign的starter依赖

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

3. 在order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到fegin-service项目中。

 4. 删除order-service中编写的UserClient、User、DefaultFeignConfiguration。

7.2.2 在order-service中使用feign-service

1. 在order-service的pom文件中中引入feign-service的依赖:

<dependency><groupId>com.zjp</groupId><artifactId>fegin-service</artifactId><version>0.0.1-SNAPSHOT</version>
</dependency>

 2. 确保order-service服务能扫描到fegin-service服务下的包

方式一:指定Feign应该扫描的包

在order-service的启动类加@EnableFeignClients(basePackages = "com.zjp.feginservice.client")

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;@EnableFeignClients(basePackages = "com.zjp.feginservice.client")
@SpringBootApplication
public class OrderServiceApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class, args);}
}

方式二:指定需要加载的Client接口

在order-service的启动类加@EnableFeignClients(clients = {UserClient.class})

import com.zjp.feginservice.client.UserClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;@EnableFeignClients(clients = {UserClient.class})
@SpringBootApplication
public class OrderServiceApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class, args);}
}

注意:

order-service项目启动时,启动类会扫描其所在的包及其子包,如果不@EnableFeignClients注解,在order-service项目启动过程中无法扫描fegin-service项目下的包,会出现以下错误:

***************************
APPLICATION FAILED TO START
***************************Description:Parameter 1 of constructor in com.zjp.orderservice.service.impl.OrderServiceImpl required a bean of type 'com.zjp.feginservice.client.UserClient' that could not be found.Action:Consider defining a bean of type 'com.zjp.feginservice.client.UserClient' in your configuration.

8. Feign的拦截器

 在order-service服务中,创建自定义的RequestInterceptor。

import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;@Slf4j
@Component
public class FeignInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate requestTemplate) {ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request = servletRequestAttributes.getRequest();log.info("===request: {}", requestTemplate.url());log.info("Request URL: {}", request.getRequestURL());log.info("Request Method: {}", request.getMethod());log.info("Request Headers: {}", request.getHeaderNames());// 设置请求头requestTemplate.header("Authorization", "Bearer token");// 将上游请求头全部设置到下游请求中Enumeration<String> headerNames = request.getHeaderNames();while (headerNames.hasMoreElements()) {String name = headerNames.nextElement();String value = request.getHeader(name);requestTemplate.header(name, value);}}
}

重启测试: 

注意:

Feign 默认情况下不会自动传递所有请求头到被调用的服务端。这是因为 Feign 有一个默认的配置,它只会传递一部分特定的请求头。如果你需要传递特定的请求头,需要手动配置。

1. 默认传递的请求头:

        1)Feign 默认会传递一些基本的请求头,如 Accept-Encoding、Connection 和 User-Agent 等。

        2)其他请求头需要手动配置才能传递。

2. 手动配置请求头:

        1)在feign接口的注解上添加headers参数,例如:

import com.zjp.common.entity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(name = "user-service")
public interface UserClient {@GetMapping(value = "/user/{id}", headers = {"Authorization: Hello World!"})User getUser(@PathVariable("id") Long id);
}

        2)通过参数传递,例如:

import com.zjp.common.entity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;@FeignClient(name = "user-service")
public interface UserClient {@GetMapping(value = "/user/{id}")User getUser(@RequestHeader("Authorization") String token, @PathVariable("id") Long id);
}

              调用时,需要手动传请求头

import com.zjp.common.entity.User;
import com.zjp.feginservice.client.UserClient;
import com.zjp.orderservice.entity.Order;
import com.zjp.orderservice.mapper.OrderMapper;
import com.zjp.orderservice.service.OrderService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;@Slf4j
@Service
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService {private final OrderMapper orderMapper;private final UserClient userClient;@Overridepublic Order getOrderById(Long id) {Order order = orderMapper.selectOrderById(id);User user = userClient.getUser("token",order.getUserId());order.setUser(user);return order;}
}

        3)通过拦截器传递请求头

9. Feign的异常捕获

9.1 自定义 ErrorDecoder

在fegin-service模块中自定义ErrorDecoder,例如:

import feign.Response;
import feign.codec.ErrorDecoder;
import lombok.extern.slf4j.Slf4j;@Slf4j
public class CustomErrorDecoder implements ErrorDecoder {private final ErrorDecoder defaultErrorDecoder = new Default();@Overridepublic Exception decode(String s, Response response) {if (response.status() > 200) {log.error("请求失败");return new RuntimeException("请求失败");} else {return defaultErrorDecoder.decode(s, response);}}
}

将 CustomErrorDecoder配置到feign接口:

import com.zjp.common.entity.User;
import com.zjp.feginservice.client.decoder.CustomErrorDecoder;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(name = "user-service", configuration = CustomErrorDecoder.class)
public interface UserClient {@GetMapping(value = "/user/{id}")User getUser(@PathVariable("id") Long id);
}

注意:

  1.  ErrorDecoder与fallback的执行顺序:先走ErrorDecoder拦截器,再走熔断的fallback。
  2. @FeignClient加上decode404 = true这一个参数,Feign对于2XX和404 ,都不会走Fallback了。 

10. 常见报错

10.1 feign接口注入失败

  • 包扫描路径问题
  • 没有添加注册中心的依赖,无法从注册中心拉取ip地址和端口;
  • 如果是单元测试,注意junit的版本,如果是4.X的版本需要在测试类上添加@Runwith;
  • 没有做到依赖最小化,加入一些无关依赖;
  • 启动类的包名层级只有一层,如只在com包下。

10.2 feign接口调用失败

  • 检查feign接口的url地址,需要跟controller的完整的url保持一致;

  • 检查feign接口的参数,参数上的@RequestParam注解不能省略;

  • 检查接口的返回值,是否漏掉了泛型信息,如果没加分型,默认元素类型是LinkedHashMap;

  • @EnableFeignClients 注解没有指定需要扫描的包/类;

  • 更新代码却未重启服务;

  • 其他情况需要开启feign日志,逐步排查。

相关文章:

OpenFeign 入门与实战:快速搭建 Spring Cloud 微服务客户端

1. 前言 随着微服务架构的流行&#xff0c;服务之间的通信变得越来越重要。Spring Cloud 提供了一系列工具来帮助开发者构建分布式系统&#xff0c;其中 OpenFeign 是一个轻量级的 HTTP 客户端&#xff0c;它简化了 Web 服务客户端的开发。本文将介绍如何在 Spring Cloud 应用…...

上门按摩系统开发方案源码搭建

上门按摩系统开发方案 一、项目概述 上门按摩系统是一个连接按摩技师和客户的平台&#xff0c;旨在提供便捷、高效的上门按摩服务。通过该系统&#xff0c;客户可以轻松预约合适的按摩技师&#xff0c;并享受个性化的按摩服务。 二、系统功能模块 用户管理模块&#xff1a;…...

【数据结构】宜宾大学-计院-实验四

栈和队列之&#xff08;栈的基本操作&#xff09; 实验目的&#xff1a;实验内容&#xff1a;实验结果&#xff1a;实验报告:&#xff08;及时撰写实验报告&#xff09;&#xff1a;实验测试结果&#xff1a;代码实现1.0&#xff1a;&#xff08;C/C&#xff09;【含注释】代码…...

selenium的IDE插件进行录制和回放并导出为python/java脚本(10)

Selenium IDE&#xff1a;Selenium Suite下的开源Web自动化测试工具&#xff0c;是Firefox或者chrome的一个插件&#xff0c;具有记录和回放功能&#xff0c;无需编程即可创建测试用例&#xff0c;并且可以将用例直接导出为可用的python/java等编程语言的脚本。 我们以chrome浏…...

从0到1封装一个image/pdf预览组件

iShot_2024-10-14_16.47.10 目录结构 content.vue <template><div class"no-content-block"><i class"iconfont icondocument large-file" /><div class"text-wrapper">{{ t(__ui__.siPreview.previewSupported) }}<…...

Android build子系统(02)Ninja语法与复杂依赖构建解读

说明&#xff1a;本文将解读Ninja构建系统的基础语法和应用&#xff0c;同时给出一些示例便于理解和学习&#xff1b;给出一个复杂构建的基础demo&#xff0c;通过这个demo的分析理解复杂构建的内在逻辑和build.ninja编写法则&#xff1b;最后扩展之前Android Framework中构建b…...

JavaScript的第三天

目录 JS中的循环&#xff0c;使某些代码重复执行 一、for循环&#xff1a;重复执行某段代码&#xff0c;通常用于计数 1、for的语法结构 2、代码解析 3、代码尝试 4、循环重复相同的代码&#xff0c;可以让用户控制输出的次数&#xff08;对该变量进行遍历&#xff09; 5、循环…...

初识git · 有关模型

目录 前言&#xff1a; 有关开发模型 前言&#xff1a; 其实文章更新到这里的时候&#xff0c;我们已经学习了可以满足我们日常生活中的基本需求的指令了&#xff0c;但是为什么要更新本篇文章呢&#xff1f;是因为实际生活中我们对于开发工作&#xff0c;运维工作&#xff…...

基于SpringBoot+Vue+uniapp的海产品加工销售一体化管理系统的详细设计和实现(源码+lw+部署文档+讲解等)

详细视频演示 请联系我获取更详细的视频演示 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不…...

解锁机器人视觉与人工智能的潜力,从“盲人机器”改造成有视觉能力的机器人(下)

机器视觉产业链全景回顾 视觉引导机器人生态系统或产业链分为三个层次。 上游&#xff08;供应商&#xff09; 该机器人视觉系统的上游包括使其得以运行的硬件和软件提供商。硬件提供商提供工业相机、图像采集卡、图像处理器、光源设备&#xff08;LED&#xff09;、镜头、光…...

CORS预检请求配置流程图 srpingboot和uniapp

首先要会判断预检请求 还是简单请求 简单请求 预检请求 #mermaid-svg-1R9nYRa7P9Pll4AK {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-1R9nYRa7P9Pll4AK .error-icon{fill:#552222;}#mermaid-svg-1R9nYRa7P9Pll4…...

用Spring AI 做智能客服,基于私有知识库和RAG技术

Java智能客服系统运用RAG技术提升答疑精准度 基于Spring ai 的 RAG&#xff08;检索增强生成&#xff09;技术&#xff0c;Java智能客服系统能够利用私有知识库中的信息提供更准确的答疑服务。 它的核心思路是&#xff1a; 首先&#xff0c;将客服QA以Word形式导入到系统中&…...

TemporalBench:一个专注于细粒度时间理解的多模态视频理解的新基准。

2024-10-15&#xff0c;由威斯康星大学麦迪逊分校、微软研究院雷德蒙德等机构联合创建了TemporalBench&#xff0c;它通过大约10K个视频问答对&#xff0c;提供了一个独特的测试平台&#xff0c;用以评估各种时间理解和推理能力&#xff0c;如动作频率、运动幅度、事件顺序等。…...

网友提问:网上申请流量卡不通过怎么办?

网上申请流量卡不通过怎么办&#xff1f;网上办理流量卡不通过&#xff0c;说明你不符合办理此套餐的要求&#xff0c;可以选择其他套餐&#xff0c;或者其他运营商的流量卡申请试试。 我们不管是在京*、淘*、拼**哪个网站申请的流量卡&#xff0c;提交的申请信息都是由运营商…...

JavaWeb 22.Node.js_简介和安装

有时候&#xff0c;后退原来是向前 —— 24.10.7 一、什么是Node.js Node.js 是一个于 Chrome V8 的 JavaScript 运行时环境&#xff0c;可以使 JavaScript 运行在服务器端。使用 Node.js&#xff0c;可以方便地开发服务器端应用程序&#xff0c;如 Web 应用、API、后端服务&a…...

APIJSON的使用

APIJSON是一个用于简化后端接口开发的工具&#xff0c;在Java中可以按照以下步骤使用&#xff1a; 1. 引入依赖 在Java项目中&#xff0c;需要引入APIJSON的相关依赖。如果使用Maven&#xff0c;可以在pom.xml文件中添加以下依赖&#xff1a; <dependency><groupId…...

简单三步完成 Telegram 生态的 Web3 冷启动

在竞争激烈的 Web3 领域&#xff0c;强有力的启动往往能决定成败。Telegram 无疑当下最火热的流量池&#xff0c;是很多 Web3 项目冷启动阶段的必选项。 但眼看着好多项目在 Telegram 生态火速获取百万级甚至千万级别的用户&#xff0c;自己的项目要怎么开始做增长&#xff0c;…...

Go Wails 学习笔记:创建第一个项目

文章目录 1. 安装 Wails2. 创建 Wails 项目3. 项目结构4. 运行项目5. 构建项目6. 部署和发布总结 Wails 是一个用于构建跨平台桌面应用程序的框架&#xff0c;允许开发者使用前端技术&#xff08;如 HTML、CSS、JavaScript&#xff09;以及 Go 语言来开发桌面应用。本文基于官方…...

Postman使用-基础篇

前言 本教程将结合业界广为推崇和使用的RestAPI设计典范Github API&#xff0c;详细介绍Postman接口测试工具的使用方法和实战技巧。 在开始这个教程之前&#xff0c;先聊一下为什么接口测试在现软件行业如此重要&#xff1f; 为什么我们要学习Postman&#xff1f; 现代软件…...

LeetCode 202.快乐数

LeetCode 202.快乐数 C 思路&#xff1a; 用快慢指针来进行解答&#xff0c;可以将其看做一个回环链表&#xff0c;慢指针完成一次平方和操作&#xff0c;快指针完成两次平方和操作&#xff0c;当快慢指针相遇时&#xff0c;判断快慢指针是否为1(为1以后无论怎么取平方和都会为…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中&#xff0c;每个页面需要使用ref&#xff0c;onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入&#xff0c;需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

Linux nano命令的基本使用

参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时&#xff0c;显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

ui框架-文件列表展示

ui框架-文件列表展示 介绍 UI框架的文件列表展示组件&#xff0c;可以展示文件夹&#xff0c;支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项&#xff0c;适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...

【深尚想】TPS54618CQRTERQ1汽车级同步降压转换器电源芯片全面解析

1. 元器件定义与技术特点 TPS54618CQRTERQ1 是德州仪器&#xff08;TI&#xff09;推出的一款 汽车级同步降压转换器&#xff08;DC-DC开关稳压器&#xff09;&#xff0c;属于高性能电源管理芯片。核心特性包括&#xff1a; 输入电压范围&#xff1a;2.95V–6V&#xff0c;输…...