Spirng Cloud Feign[‘装作’–“安装’工作区’作业”] WebService客户端,目的:是让WebService调用更加简单。

Feign-(调用服务Client客户端 ) > 此组件优势:
- Feign 是一个声明式的Web Service(Web服务)客户端、模版化的HTTP客户端。
- 可以做到使用HTTP 请求访问远程服务/Feign会完全代理HTTP请求。
- 接口上添加@FeignClient注解-即可被SpringIoc依赖注入Bean中。
- Feingn 具备‘插拔性’ 注解。
- Feign 支持插拔的HTTP编码器和解码器/提供了HTTP请求模版。
- 支持/并整合了Hystrix(熔断机制)和它的Fallback(返回上次)。
- 增强了对Spring MVC的注解支持。
- 支持/并内整合了Ribbon(客户端-负载均衡工具)。
一、Feign入门案例
1-创建Maven工程,配置Maven依赖所示:
<!-- Spring Cloud OpenFeign的Starter的依赖 -->
  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
  </dependency>
2-创建主入口程序main()并添加类上注解:
@SpringBootApplication
@EnableFeignClients <!--该注解表示当程序启动时,会进行包扫描所有带@EnableFeign注解的类并处理-->
public class SpringCloudFeignApplication {
	public static void main(String[] args) {
		SpringApplication.run(SpringCloudFeignApplication.class, args);
	}
}
3-编写FeignClient Service接口:
@FeignClient(name = "github-client", 
	url = "https://api.github.com", configuration = HelloFeignServiceConfig.class)
<!--表示手动指定 url=“调用地址/远程服务地址”-->
public interface HelloFeignService {
    @RequestMapping(value = "/search/repositories", method = RequestMethod.GET)
    String searchRepo(@RequestParam("q") String queryStr);
}
    <!--该方法最终请求地址是:远程服务地址/方法定义路径?方法定义参数=请求参数值-->
<!--该方法最终请求地址是:https://api.github.com/search/repositories?q=spring-cloud-dubbo-->
4-编写Controoller层,并依赖注入FeignClient(Feign客户端):定义的接口类:HelloFeignService.Java
@RestController(控制层)
public class HelloFeignController {
    @Autowired
    private HelloFeignService helloFeignService;
    // 服务消费者对位提供的服务
    @GetMapping(value = "/search/github")
    public String searchGithubRepoByStr(@RequestParam("str") String queryStr) {
        return helloFeignService.searchRepo(queryStr);
    }
}
该类==class HelloFeignController==是,服务消费者类 ==searchGithubRepoByStr()== 消费者请求方法
该接口==interface HelloFeignService==是,服务提供者-定义指定地址中间组件/中间请求的‘钥匙’/Fegin组件
5-编写通过tomactWeb服务器请求-返回JSON结果集。
Feign工作原理:

步骤:
1-主程序入口添加 @EnableFeignClients 注解开启对 @FeignClient 扫描加载处理。
2-扫描所有 @FeignClient的注解的接口类,并注入SpringIOC容器中。
3-其接口类中的方法被调用是,是通过JDK的代理方式, 生成具体的RequestTemplate(请求范本)对象。1
4-然后有RequestTemplate生成Request,然后Request交给Client去处理。2
5-最后Client被封装到LoadBalanceClient类,该类结合Ribbon负载均衡发起服务之间的调用。

@FeignClient注解里做了/写了什么/?
@Target(ElementType.TYPE) --@目标(元素类型.TYPE) 标识着被注释的interface接口作用目标在接口上。
@Retention(RetentionPolicy.RUNTIME) --保留@(保留政策.RUNTIME[运行时]-可被反射读取)
@Documented --备有证明文件的(声明式)
public @interface FeignClient {
	@AliasFor("name")
	String value() default "";
	@Deprecated
	String serviceId() default "";
	@AliasFor("value")
	String name() default "";
	String qualifier() default ""

	String url() default "";
			-1. 一般用于调试,可以手动指定 @FeignClient调用地址。
	boolean decode404() default false;
			-1.-DeCode404-:当发生404错误❌时,如果该字段为true,
			-2.会调用-DeCode-进行解码,否则抛出 FeignException 异常。
	Class<?>[] configuration() default {};
			-1. Feign配置类
			-2. 可以自定义 Feign的:
				-2-1.Encoder.(编码器)
				-2-2.Decoder.(解码器)
				-2-3.LogLevel.(日志级别)
				-2-4.Contract.(协议)
				-2-5.以上属性值状态。
	Class<?> fallback() default void.class;
			-1. 定义容错的处理类:
			-2. 当调用远程接口失败或者超时时,会调用对应的容错逻辑.
			-3  fallback指定的类必须实现 @FeignClient 标识的接口。
	Class<?> fallbackFactory() default void.class;
			-1. 工厂类🏭:-回退动作工厂-
			-2. 用户生成-fakkBack类-示例;
			-3. 通过这个属性可以实现每个接口通用的容错逻辑,减少重复的代码。
	String path() default "";
			-1.-path-定义当前 FeignClient的统一前缀。
	boolean primary() default true;
	
			-- 剩下的字段标识的意思,等大伙儿开问嘞 --
}

Feign 组件开启 ‘霸气模式’ 哈~~~

二、Feign开始GZIP压缩

1-支持对Request请求和Response响应-TransferInfo传输信息进行GZIP压缩,提高通信效率。

-上代码

- 配置—Appliction.YML
feign:
    compression:
        request:
            enabled: true
            # 配置压缩支持的MIME TYPE
            mime-types: text/xml,application/xml,application/json
            min-request-size: 2048  # 配置压缩数据大小的下限
        response:
            enabled: true # 配置响应GZIP压缩

开启GZIP压缩之后,Feign之间的调用通过二进制协议进行Transfer传输,其返回值需要修改为ResposeEntity<byte[]>才可以正常显示。👇代码👇

@FeignClient(name = "github-client", url = "https://api.github.com",
 				configuration = HelloFeignServiceConfig.class)
public interface HelloFeignService {
    @RequestMapping(value = "/search/repositories", method = RequestMethod.GET)
    ResponseEntity<byte[]> searchRepo(@RequestParam("q") String queryStr);
}
- 然后,启动主应用程序,打开浏览器访问正确URL-结果集会响应JSON格式Info。
三、Feign支持属性文件配置

-看配置信息文件

-1-对单个指定特定名称对Feign进行设置:
feign:
  client:
    config:
      feignName: #需要配置的FeignName
      connectTimeout: 5000 #连接超时时间
      readTimeout: 5000 #读超时时间设置
      looggerLevel: full #配置Feign的日志级别
      errorDecoder: com.example.SimpleErrorDecoder #Feign的错误❌解码器
      retryer: com.example.SimpleRetryer #配置重试
      requestInterceptors: -com.example.FooRequestInterceptor 
      						-com.example.BarRequestInterceptor #配置拦截器
      decode404: false
      encoder: com.example.SimpleEncoder # Feign的编码器
      decoder: com.example.SimpleDecoder # Feign的解码器
      contract: com.example,SimpleContract #Feign的Contract配置
-2-此方式作用于所有Feign配置方式:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
			........
	Class<?>[] defaultConfiguration() default {};
			-1. 使用-@EnableFeignClients-注解类中的该属性,
			-2. 可以将默认配置写成一个类--....
			-3. 比如:-创建配置类 'DefaultFeignConfiguration.java',
			-4. 然后,在主程序的启动入口使用 defaultConfiguration()来引用-自定义配置类;
					.........
}

– 展示主程序类上 ‘Annotation注解’

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

- 兜兜转转一圈二,大家该理解了吧!!!

-3-配置全局Feign属性值:
feign: 
  client:
    config:
       defailt:
            connectTimeout: 5000
            readTimeout: 5000
            loggerLevel: basic

注意 ⚠️⚠️⚠️:如果通过Java代码配置过Feign设置属性类,然后又通过属性文件的方式配置Feign;
| | | | | | | | | | 后者一定会覆盖前者的设置的,但可以配置feign.client.defult-to-properties=false,
| | | | | | | | | | 来改变Feign设置的生效的优先级。

四、Feign Client开启日志

-Feign 为每一个FeignClient都提供来一个 ‘Feign.Logger’ 实例,可以在配置中开启日志。

-步骤1:

'-在application.yml-中设置日志输出级别'
logging:
     level:
       cn.springcloud.book.feign.service.HelloFeignService: debug

-步骤2:

-1- 通过创建带有-@Configuration-注解的配置类,
					-2- 去配置Bean,代码👇下面👇
@Configuration
public class HelloFeignServiceConfig {
    /**
     *
     * Logger.Level 的具体级别如下:
         NONE:不记录任何信息
         BASIC:仅记录请求方法、URL以及响应状态码和执行时间
         HEADERS:除了记录 BASIC级别的信息外,还会记录请求和响应的头信息
         FULL:记录所有请求与响应的明细,包括头信息、请求体、元数据
     * @return
     */
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}
五、Feign-超时设置

-Feign的设置分两层,即Ribbon(客户端负载均衡)和Hystrix(熔断器)的调用,Hystrix默认是关闭的。
-当Feign和Ribbon整合了Hystrix之后,可能会出现首次调用失败问题,
-造成问题出现的原因分析如下:
–1.Hystrix 默认的超时时间是1秒.超过时间未做出响应,将进入FallBack(后退动作)代码。
–2.由于Bean的装配以及懒加载机制等,Feign首次请求都会比较慢。
–3.解决方式:(1)将Hystrix的超时时间调整大,例如- 5 秒
--4. hystrix.command.default.exexcution.isolation.thread.timeoutlnMilliseconds:5000 –5.(2)禁用超时时间
--6.hystrix.command.default.execution.timeout.enabled:false –7 (3)使用Feign的时候直接关闭Hystrix,该方式不推荐使用
–8.feign.hystrix.enabled.false
1)Ribbon超时设置:ribbon.ReadTimeout: 120000 # 设置请求处理的超时时间ribbon.ConnectTimeout:30000 # 设置请求连接的超时时间

> 2)Hystrix超时设置:
 feign.hystrix.enabled: truehystrix #熔断机制
 	hystrix: 
 		shareSecurityContext: true
 		command:
 		default:
 		circuitBreaker:
 		sleepWindowInMillisecodes: 100000
 		forceClosed: true
 		execution:
 		isolation:
 		thread:
 	timeoutInMillisecods: 600000
六、Feign默认Client 2

Feigin 在默认情况下使用的JDK原生的Client 2,没有连接池的。

-1-使用HTTP Client2替换Feign默认Client2
<!-- 使用Apache HttpClient替换Feign原生httpclient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>

        <dependency>
            <groupId>com.netflix.feign</groupId>
            <artifactId>feign-httpclient</artifactId>
            <version>8.17.0</version>
        </dependency>
feign:
  httpclient:
      enabled: true
- 然后,启动Java主程序访问即可。
-2-使用 OkHttp2替换Feign默认Client2
<dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
    </dependency>
feign:
    httpclient:
         enabled: false
    okhttp:
         enabled: true
-3-使用 OkHttp2第二种方式 FeignOkHttpConfig.Java 配置类 替换Feign默认Client2
@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignOkHttpConfig {
    @Bean
    public okhttp3.OkHttpClient okHttpClient(){
        return new okhttp3.OkHttpClient.Builder()
                 //设置连接超时
                .connectTimeout(60, TimeUnit.SECONDS)
                //设置读超时
                .readTimeout(60, TimeUnit.SECONDS)
                //设置写超时
                .writeTimeout(60,TimeUnit.SECONDS)
                //是否自动重连
                .retryOnConnectionFailure(true)
                .connectionPool(new ConnectionPool())
                //构建OkHttpClient对象
                .build();
    }
}
- 最后,启动Java主程序访问即可。
六、Feign的Post()和Get() 两种方式多参数传递-通过Feign拦截器方式处理

大家儿都知道,在Web开发中Spring MVC 是支持Get()方法直接绑定POJO(实体类)的,
最常见的解决方式如下:
1- 把POJO(实体类)拆散成一个一个单独的属性放在方法参数里。
2- 把方法参数变成Map传递。
3- 使用Get传递@RequesBody,但此方式违反Restful规范。
--------------------------------------------------------------------------- 666
下面我使用Feign拦截器的方式处理–:

表6-1 多参数传递工程集合

工程名

端口

描述

R6-1-Eureka-Server

8761

注册中心

R6-1-Consumer

8011

GET或POST 请求多个参数传递的服务消费者,集成了Swagger用于测试

R6-1-Provider

8012

GET或POST 请求多参数传递的服务提供者

<!-- R6-1-Consumer 工程 Maven-->
  		<!-- Spring Cloud OpenFeign的Starter的依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- Swagger 的依赖 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.5.0</version>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.5.0</version>
        </dependency>
<!-- R6-1-Consumer 工程 application.yml-->
server:
  port: 8011
spring:
  application:
    name: r6-1-consumer
    
eureka:
  client:
    service-url:
           defaultZone: http://localhost:8761/eureka
<!-- R6-1-Consumer 工程 配置Swagger Config类集-->
(1)
@Configuration
@EnableWebMvc
public class ApplicationExceptionAdapter extends WebMvcConfigurerAdapter {
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("swagger-ui.html")
				.addResourceLocations("classpath:/META-INF/resources/");
		registry.addResourceHandler("/webjars/**")
				.addResourceLocations("classpath:/META-INF/resources/webjars/");
	}
}
(2)
@Configuration
@EnableSwagger2
public class Swagger2Config {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
                .apis(RequestHandlerSelectors
                        .basePackage("cn.springcloud.book.feign.controller"))
                .paths(PathSelectors.any()).build();
    }
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder().title("Feign多参数传递问题").description("Feign多参数传递问题")
                .contact("Software_King@qq.com").version("1.0").build();
    }
}
<!-- R6-1-Consumer 工程 自定义拦截器类-->
@Component
public class FeignRequestInterceptor implements RequestInterceptor {
    @Autowired
    private ObjectMapper objectMapper;
    @Override
    public void apply(RequestTemplate template) {
        // feign 不支持 GET 方法传 POJO, json body转query
        if (template.method().equals("GET") && template.body() != null) {
            try {
                JsonNode jsonNode = objectMapper.readTree(template.body());
                template.body(null);

                Map<String, Collection<String>> queries = new HashMap<>();
                buildQuery(jsonNode, "", queries);
                template.queries(queries);
            } catch (IOException e) {
                //提示:根据实践项目情况处理此处异常,这里不做扩展。
                e.printStackTrace();
            }
        }
    }
}
<!-- R6-1-Consumer 工程 Controller层-->
@RestController
@RequestMapping("/user")
public class UserController {
	@Autowired
	private UserFeignService userFeignService;
	/*** 用于演示Feign的Get请求多参数传递  * @param user  * @return */
	@RequestMapping(value = "/add", method = RequestMethod.POST)
	public String addUser( @RequestBody 
				@ApiParam(name="用户",value="传入json格式",required=true) User user){
		return userFeignService.addUser(user);
	}
	 /** * 用于演示Feign的Post请求多参数传递  * @param user * @return*/
	@RequestMapping(value = "/update", method = RequestMethod.POST)
	public String updateUser( @RequestBody 
				@ApiParam(name="用户",value="传入json格式",required=true) User user){
		return userFeignService.updateUser(user);
	}
}
<!-- R6-1-Consumer 工程 Feign远程调用服务层-->
@FeignClient(name = "R6-1-Provider ")
public interface UserFeignService {
    @RequestMapping(value = "/user/add", method = RequestMethod.GET)
    public String addUser(User user);
    @RequestMapping(value = "/user/update", method = RequestMethod.POST)
    public String updateUser(@RequestBody User user);
}
<!-- R6-1-Consumer 工程 POJO实体类-->
public class User {
    private Long id;
    private String name;
    private int age;
    public Long getId() {return id;}
    public void setId(Long id) {this.id = id;}
    public String getName() {return name;}
    public void setName(String name) {his.name = name;}
    public int getAge() {return age;{}
    public void setAge(int age) {this.age = age;}
}
<!-- R6-1-Provider 工程 application.yml-->
server:
  port: 8012
spring:
  application:
    name: r6-1-provider
eureka:
    client:
      serviceUrl:
        defaultZone: http://localhost:8761/eureka/
   #eureka.instance.prefer-ip-address  表示将自己的IP注册到Eureka Server上,
   #如果不配置,会将当前服务提供者所在的主机名注册到Eureka Server上。
    instance:
      prefer-ip-address: true
<!-- R6-1-Provider 工程 Controller层-->
@RestController
@RequestMapping("/user")
public class UserController {
	@RequestMapping(value = "/add", method = RequestMethod.GET)
	public String addUser(User user , HttpServletRequest request){
		String token=request.getHeader("oauthToken");
		return "hello,"+user.getName();
	}
	@RequestMapping(value = "/update", method = RequestMethod.POST)
	public String updateUser( @RequestBody User user){
		return "hello,"+user.getName();
	}
}
<!-- R6-1-Eureka-Server 工程 Maven-->
	<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<!-- springboot web -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
			<exclusions>
				<exclusion>
					<artifactId>spring-boot-starter-tomcat</artifactId>
					<groupId>org.springframework.boot</groupId>
				</exclusion>
			</exclusions>
		</dependency>
		<!--不用Tomcat,使用undertow -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-undertow</artifactId>
		</dependency>
		<dependency>
			<groupId>io.undertow</groupId>
			<artifactId>undertow-servlet</artifactId>
		</dependency>
<!-- R6-1-Eureka-Server 工程 bootstrap.yml -->
server:
  port: 8761
eureka:
  instance:
    hostname: localhost
  server :
    enable-self-preservation: false
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
- Swagger访问测试页面:http://localhost:8011/swagger-ui.html
- 大头儿复制粘贴完,分别启动各项目的Java主程序访问即可。
七、Feign的文件上传
表7-1 文件上传工程列表

工程名

端口

描述

R7-1-Eureka-Server

8761

注册中心(之前上面👆自己找)

R7-1-Feign-File-Server

8012

模拟文件服务器,服务提供者

R7-1-Feign-Upload-Client

8011

模拟文件表单上传,通过FeignClient发送文件到文件服务器(集成了Swagger 上面代码👆有)

<!-- R7-1-Feign-Upload-Client 工程 Mavne -->
        <!-- Feign文件上传依赖-->
        <dependency>
            <groupId>io.github.openfeign.form</groupId>
            <artifactId>feign-form</artifactId>
            <version>3.0.3</version>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign.form</groupId>
            <artifactId>feign-form-spring</artifactId>
            <version>3.0.3</version>
        </dependency>
<!-- R7-1-Feign-Upload-Client 工程 Service层-->
@FeignClient(value = "feign-file-server",
	 configuration = FeignMultipartSupportConfig.class)
public interface FileUploadFeignService {
 /**** 1.produces,consumes必填
     * 2.注意区分@RequestPart和RequestParam,不要将
     * * @RequestPart(value = "file") 写成@RequestParam(value = "file")
     * * @param file* @return*/
    @RequestMapping(method = RequestMethod.POST, value = "/uploadFile/server",
            produces = {MediaType.APPLICATION_JSON_UTF8_VALUE},
            consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public  String fileUpload(@RequestPart(value = "file") MultipartFile file);
}
<!-- R7-1-Feign-Upload-Client 工程 Controller层-->
@RestController
@Api(value="文件上传")
@RequestMapping("/feign")
public class FeignUploadController {
    @Autowired
    private FileUploadFeignService fileUploadFeignService;
    @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    @ApiOperation(value = "文件上传", notes = "请选择文件上传" )
    public String imageUpload(@ApiParam(value="文件上传",required = true)  
    MultipartFile file ) throws Exception{
        return fileUploadFeignService.fileUpload(file);
    }
}
<!-- R7-1-Feign-Upload-Client 工程 Config层-->
/*** Feign文件上传Configuration*/
@Configuration
public class FeignMultipartSupportConfig {
    @Bean
    @Primary
    @Scope("prototype")
    public Encoder multipartFormEncoder() {
        return new SpringFormEncoder();
    }
}
- 大头儿二复制粘贴完,分别启动各项目的Java主程序访问即可。
八、Feign调用传递Token

-1 在进行认证鉴权的时候,不管是JWT认证 3 ,还是 Spring Security(安全性) 4 验证。
-2 当使用Feign时就会发现外部请求到A服务的时候,A服务是可以拿到Token的,
-3 然而当服务使用Feign调用是,Token就会小时,从而认证失败。
-4 解决方案:需要做当就是Feign调用时候,向Header(请求头)添加需要传递的Toten。

<!-- 首先需要实现Feign提供的一个接口RequestInterceptor,假设我们在验证权限的时候
		放在请求头里面的key为oauthToken,先获取当前请求中的key为oauthToken的TOken,
			然后放到Feign的请求Header上。-->
/*** Feign统一Token拦截器*/
@Component
public class FeignTokenInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        if(null==getHttpServletRequest()){
            //此处省略日志记录
            return;
        }
        //将获取Token对应的值往下面传
        requestTemplate.header("oauthToken", 
        getHeaders(getHttpServletRequest()).get("oauthToken"));
    }

    private HttpServletRequest getHttpServletRequest() {
        try {
            return ((ServletRequestAttributes) 
            RequestContextHolder.getRequestAttributes()).getRequest();
        } catch (Exception e) {
            return null;
        }
    }

    /** * Feign拦截器拦截请求获取Token对应的值
     * @param request  * @return */
    private Map<String, String> getHeaders(HttpServletRequest request) {
        Map<String, String> map = new LinkedHashMap<>();
        Enumeration<String> enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String key = enumeration.nextElement();
            String value = request.getHeader(key);
            map.put(key, value);
        }
        return map;
    }
}

小结:哼~ 哼~ 哼 ! ! ! 总算将它‘码’完了。乐意为‘码’同志 解答噢 !!!


  • RequestTemplate(请求范本)对象:“该对象封装了HTTP请求需要的全部信息,如:请求参数名、请求方法名、等信息。都是在这个过程中确定的。”
  • ↩︎
  • Client 在此指:可以是JDK原生的URLConnection、Apache的Http Client,也可以是Okhttp。
    – 默认情况下使用的是JDK原生的URLConnection发送HTTP请求,没有连接池,但是对每个地址会保持一个长连接,即利用HTTP的 Persistence Connection(持续连接)。
    – Apache Http Client 可设置连接池、超时时间等对服务之间的调用调优。
    – OkHttp 是一个很棒的HTTP客户端,具有以下功能和特性:
    – 支持SPDY,可以合并多个到同一个主机的请求。
    – 使用连接池技术减少请求的延长。
    – 使用GZIP压缩减少传输的数据量。
    – 缓存响应避免重复的网络请求。
  • ↩︎↩︎↩︎↩︎↩︎↩︎↩︎↩︎↩︎
  • JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。
    – JWT 工作流程:
    – 1.用户导航到登录页,输入用户名、密码,进行登录
    – 2.服务器验证登录鉴权,如果用户合法,根据用户的信息和服务器的规则生成JWT Token
    – 3.服务器将该token以json形式返回(不一定要json形式,这里说的是一种常见的做法)
    – 4.用户得到token,存在localStorage、cookie或其它数据存储形式中。
    – 5.以后用户请求/protected中的API时,在请求的header中加入 Authorization: Bearer xxxx(token)。此处注意token之前有一个7字符长度的 Bearer
    – 6.服务器端对此token进行检验,如果合法就解析其中内容,根据其拥有的权限和自己的业务逻辑给出对应的响应结果。
    – 7.用户取得结果
  • ↩︎
  • Spring Security(安全性) 是为基于Spring的应用程序提供声明式安全保护的安全性框架。
    – Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)
  • ↩︎