精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Java 聲明式 Http 接口對接框架

開發(fā) 前端
與其說的是對接的Http接口,不如說是對接的第三方渠道,UniHttp可支持自定義接口渠道方HttpAPI注解以及一些自定義的對接和交互行為 ,為此擴展了發(fā)送和響應(yīng)和反序列化一個Http請求的各種生命周期鉤子,開發(fā)者可自行去擴展實現(xiàn)。

1、簡介

一個聲明式的Http接口對接框架,能以極快的方式完成對一個第三方Http接口的對接和使用,之后就像調(diào)用本地方法一樣自動去發(fā)起Http請求,不需要開發(fā)者去關(guān)注如何發(fā)送一個請求,如何去傳遞Http請求參數(shù),以及如何對請求結(jié)果進行處理和反序列化,這些框架都幫你一一實現(xiàn)

就像配置 Spring的Controller 那樣簡單,只不過相當(dāng)于是反向配置而已

該框架更注重于如何保持高內(nèi)聚和可讀性高的代碼情況下與快速第三方渠道接口進行對接和集成,而非像傳統(tǒng)編程式的Http請求客戶端(比如HttpClient、Okhttp)那樣專注于如何去發(fā)送Http請求,雖然底層也是用的Okhttp去發(fā)送請求。

與其說的是對接的Http接口,不如說是對接的第三方渠道,UniHttp可支持自定義接口渠道方HttpAPI注解以及一些自定義的對接和交互行為 ,為此擴展了發(fā)送和響應(yīng)和反序列化一個Http請求的各種生命周期鉤子,開發(fā)者可自行去擴展實現(xiàn)。

2、快速開始

2.1、引入依賴

<dependency>
  <groupId>io.github.burukeyou</groupId>
  <artifactId>uniapi-http</artifactId>
  <version>0.0.4</version>
</dependency>

2.2、對接接口

首先隨便創(chuàng)建一個接口,然后在接口上標(biāo)記@HttpApi注解,然后指定請求的域名url, 然后就可以在方法上去配置對接哪個接口。

比如下面兩個方法的配置則對接了以下兩個接口

  • GET http://localhost:8080/getUser
  • POST http://localhost:8080/addUser

方法返回值定義成Http響應(yīng)body對應(yīng)的類型即可,默認(rèn)會使用fastjson反序列化Http響應(yīng)body的值為該類型對象。

@HttpApi(url = "http://localhost:8080")
interface UserHttpApi {
    
   @GetHttpInterface("/getUser")
   BaseRsp<String> getUser(@QueryPar("name") String param,@HeaderPar("userId") Integer id);
    
   @PostHttpInterface("/addUser")
   BaseRsp<Add4DTO> addUser(@BodyJsonPar Add4DTO req);
   
}
  • @QueryPar  表示將參數(shù)值放到Http請求的查詢參數(shù)內(nèi)
  • @HeaderPar   表示將參數(shù)值放到Http請求的請求頭里
  • @BodyJsonPar 表示將參數(shù)值放到Http請求body內(nèi),并且content-type是application/json
1)getUser方法最終構(gòu)建的Http請求報文為
GET http://localhost:8080/getUser?name=param
Header:
    userId: id
2)addUser最終構(gòu)建的Http請求報文為
POST:  http://localhost:8080/addUser 
Header: 
    Content-Type:   application/json
Body:
    {"id":1,"name":"jay"}

2.3、聲明定義的HttpAPI的包掃描路徑

在spring的配置類上使用@UniAPIScan注解標(biāo)記定義的@HttpAPI的包掃描路徑,會自動為標(biāo)記了@HttpApi接口生成代理對象并且注入到Spring容器中,之后只需要像使用Spring的其他bean一樣,依賴注入使用即可

@UniAPIScan("com.xxx.demo.api")
@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class,args);
    }
}

2.4、依賴注入使用即可

@Service
class UserAppService {
    
    @Autowired
    private UserHttpApi userHttpApi;
    
    public void doSomething(){
        userHttpApi.getUser("jay",3);
    }
}

3、說明介紹

3.1、@HttpApi注解

用于標(biāo)記接口上,該接口上的方法會被代理到對應(yīng)的Http請求接口,可指定請求的域名,也可指定自定義的Http代理邏輯等等。

3.2、@HttpInterface注解

用于配置一個接口的參數(shù),包括請求方式、請求路徑、請求頭、請求cookie、請求查詢參數(shù)等等

并且內(nèi)置了以下請求方式的@HttpInterface,不必再每次手動指定請求方式

  • @PostHttpInterface
  • @PutHttpInterface
  • @DeleteHttpInterface
  • @GetHttpInterface
@PostHttpInterface(
    // 請求路徑
    path = "/getUser",
    // 請求頭
    headers = {"clientType:sys-app","userId:99"},
    // url查詢參數(shù) 
    params = {"name=周杰倫","age=1"},
    // url查詢參數(shù)拼接字符串
    paramStr = "a=1&b=2&c=3&d=哈哈&e=%E7%89%9B%E9%80%BC",
    // cookie 字符串
    cookie = "name=1;sessionId=999"
)
BaseRsp<String> getUser();

3.3、@Par注解

以下各種Par后綴的注解,主要用于方法參數(shù)上,用于指定在發(fā)送請求時將參數(shù)值放到Http請求體的哪部分上。

為了方便描述,下文描述的普通值就是表示String,基本類型、基本類型的包裝類型等類型.

簡單復(fù)習(xí)下Http協(xié)議報文

圖片圖片

@QueryPar注解

標(biāo)記Http請求url的查詢參數(shù)

支持以下方法參數(shù)類型的標(biāo)記: 普通值、普通值集合、對象、Map

@PostHttpInterface
BaseRsp<String> getUser(@QueryPar("id")  String id,  //  普通值   
                        @QueryPar("ids") List<Integer> idsList, //  普通值集合
                        @QueryPar User user,  // 對象
                        @QueryPar Map<String,Object> map); // Map

如果類型是普通值或者普通值集合需要手動指定參數(shù)名,因為是當(dāng)成單個查詢參數(shù)傳遞

如果類型是對象或者Map是當(dāng)成多個查詢參數(shù)傳遞,字段名或者map的key名就是參數(shù)名,字段值或者map的value值就是參數(shù)值。

如果是對象,參數(shù)名默認(rèn)是字段名,由于用的是fastjson序列化可以用@JSONField指定別名

@PathPar注解

標(biāo)記Http請求路徑變量參數(shù),僅支持標(biāo)記普通值類型

@PostHttpInterface("/getUser/{userId}/detail")
BaseRsp<String> getUser(@PathPar("userId")  String id);  //  普通值
@HeaderPar注解

標(biāo)記Http請求頭參數(shù)

支持以下方法參數(shù)類型:對象、Map、普通值

@PostHttpInterface
BaseRsp<String> getUser(@HeaderPar("id")  String id,  //  普通值   
                        @HeaderPar User user,  // 對象
                        @HeaderPar Map<String,Object> map); // Map

如果類型是普通值類型需要手動指定參數(shù)名,當(dāng)成單個請求頭參數(shù)傳遞. 如果是對象或者Map當(dāng)成多個請求頭參數(shù)。

@CookiePar注解

用于標(biāo)記Http請求的cookie請求頭

支持以下方法參數(shù)類型: Map、Cookie對象、字符串

@PostHttpInterface
BaseRsp<String> getUser(@CookiePar("id")  String cookiePar,  //   普通值 (指定name)當(dāng)成單個cookie鍵值對處理
                        @CookiePar String cookieString,  //  普通值 (不指定name),當(dāng)成完整的cookie字符串處理
                        @CookiePar com.burukeyou.uniapi.http.support.Cookie cookieObj,  // 單個Cookie對象 
                        @CookiePar List<com.burukeyou.uniapi.http.support.Cookie> cookieList // Cookie對象列表
                        @CookiePar Map<String,Object> map); // Map

如果類型是字符串時,當(dāng)指定參數(shù)名時,當(dāng)成單個cookie鍵值對處理,如果不指定參數(shù)名時當(dāng)成完整的cookie字符串處理比如a=1;b=2;c=3 這樣

如果是Map當(dāng)成多個cookie鍵值對處理。

如果類型是內(nèi)置的 com.burukeyou.uniapi.http.support.Cookie對象當(dāng)成單個cookie鍵值對處理

@BodyJsonPar注解

用于標(biāo)記Http請求體內(nèi)容為json形式: 對應(yīng)content-type為 application/json

支持以下方法參數(shù)類型: 對象、對象集合、Map、普通值、普通值集合

@PostHttpInterface
BaseRsp<String> getUser(@BodyJsonPar  String id,                //  普通值
                        @BodyJsonPar  String[] id               //  普通值集合
                        @BodyJsonPar List<User> userList,       // 對象集合
                        @BodyJsonPar User user,                  // 對象
                        @BodyJsonPar Map<String,Object> map);    // Map

序列化和反序列化默認(rèn)用的是fastjson,所以如果想指定別名,可以在字段上標(biāo)記 @JSONField 注解取別名

@BodyFormPar注解

用于標(biāo)記Http請求體內(nèi)容為普通表單形式: 對應(yīng)content-type為 application/x-www-form-urlencoded

支持以下方法參數(shù)類型:對象、Map、普通值

@PostHttpInterface
BaseRsp<String> getUser(@BodyFormPar("name") String value,         //  普通值
                        @BodyFormPar User user,                   // 對象
                        @BodyFormPar Map<String,Object> map);    // Map

如果類型是普通值類型需要手動指定參數(shù)名,當(dāng)成單個請求表單鍵值對傳遞

@BodyMultiPartPar注解

用于標(biāo)記Http請求體內(nèi)容為復(fù)雜形式: 對應(yīng)content-type為 multipart/form-data

支持以下方法參數(shù)類型: 對象、Map、普通值、File對象

@PostHttpInterface
BaseRsp<String> getUser(@BodyMultiPartPar("name") String value,         //  單個表單文本值
                        @BodyMultiPartPar User user,                   // 對象
                        @BodyMultiPartPar Map<String,Object> map,      // Map
                        @BodyMultiPartPar("userImg") File file);     // 單個表單文件值

如果參數(shù)類型是普通值或者File類型,當(dāng)成單個表單鍵值對處理,需要手動指定參數(shù)名。

如果參數(shù)類型是對象或者Map,當(dāng)成多個表單鍵值對處理。如果字段值或者map的value參數(shù)值是File類型,則自動當(dāng)成是文件表單字段傳遞處理

@BodyBinaryPar注解

用于標(biāo)記Http請求體內(nèi)容為二進制形式: 對應(yīng)content-type為 application/octet-stream

支持以下方法參數(shù)類型: InputStream、File、InputStreamSource

@PostHttpInterface
BaseRsp<String> getUser(@BodyBinaryPar InputStream value,         
                        @BodyBinaryPar File user,                   
                        @BodyBinaryPar InputStreamSource map);
@ComposePar注解

這個注解本身不是對Http請求內(nèi)容的配置,僅用于標(biāo)記一個對象,然后會對該對象內(nèi)的所有標(biāo)記了其他@Par注解的字段進行嵌套解析處理, 目的是減少方法參數(shù)數(shù)量,支持都內(nèi)聚到一起傳遞

支持以下方法參數(shù)類型: 對象

@PostHttpInterface
BaseRsp<String> getUser(@ComposePar UserReq req);

比如UserReq里面的字段可以嵌套標(biāo)記其他@Par注解,具體支持的標(biāo)記類型和處理邏輯與前面一致

class UserReq {

    @QueryPar
    private Long id;

    @HeaderPar
    private String name;

    @BodyJsonPar
    private Add4DTO req;

    @CookiePar
    private String cook;
}

3.4、原始的HttpResponse

HttpResponse表示Http請求的原始響應(yīng)對象,如果業(yè)務(wù)需要關(guān)注拿到完整的Http響應(yīng),只需要在方法返回值包裝返回即可。

如下面所示,此時HttpResponse<Add4DTO>里的泛型Add4DTO才是代表接口實際返回的響應(yīng)內(nèi)容,后續(xù)可直接手動獲取

@PostHttpInterface("/user-web/get")
HttpResponse<Add4DTO> get();

通過它我們就可以拿到響應(yīng)的Http狀態(tài)碼、響應(yīng)頭、響應(yīng)cookie等等,當(dāng)然也可以拿到我們的響應(yīng)body的內(nèi)容通過getBodyResult方法

3.5、處理文件下載接口

對于若是下載文件的類型的接口,可將方法返回值定義為 HttpBinaryResponse、HttpFileResponse、HttpInputStreamResponse 的任意一種,這樣就可以拿到下載后的文件。

  • HttpBinaryResponse: 表示下載的文件內(nèi)容以二進制形式返回,如果是大文件請謹(jǐn)慎處理,因為會存放在內(nèi)存中
  • HttpFileResponse:  表示下載的文件內(nèi)容以File對象返回,這時文件已經(jīng)被下載到了本地磁盤
  • HttpInputStreamResponse: 表示下載的文件內(nèi)容輸入流的形式返回,這時文件其實還沒被下載到客戶端,調(diào)用者可以自行讀取該輸入流進行文件的下載

3.6、HttpApiProcessor 生命周期鉤子

HttpApiProcessor是一個Http請求接口的各種生命周期鉤子,開發(fā)者可以實現(xiàn)它在里面自定義編寫各種對接邏輯。然后可以配置到@HttpApi注解或者@HttpInterface注解上, 然后框架內(nèi)部默認(rèn)會從SpringContext獲取,獲取不到則手動new一個。

通常一個Http請求需要經(jīng)歷 構(gòu)建請求參數(shù)、發(fā)送Http請求時,Http響應(yīng)后獲取響應(yīng)內(nèi)容、反序列化Http響應(yīng)內(nèi)容成具體對象。

目前提供了4種鉤子,執(zhí)行順序流程如下:

postBeforeHttpMetadata  (請求發(fā)送前)在發(fā)送請求之前,對Http請求體后置處理
           |
           V
postSendingHttpRequest  (請求發(fā)送時)在Http請求發(fā)送時處理
           |
           V
postAfterHttpResponseBodyString  (請求響應(yīng)后)對響應(yīng)body文本字符串進行后置處理
           |
           V
postAfterHttpResponseBodyResult  (請求響應(yīng)后)對響應(yīng)body反序列化后的結(jié)果進行后置處理
           |
           V
postAfterMethodReturnValue  (請求響應(yīng)后)對代理的方法的返回值進行后置處理,類似aop的后置處理
  • postBeforeHttpMetadata: 可在發(fā)送http請求之前對請求體進行二次處理,比如加簽之類
  • postSendHttpRequest:   Http請求發(fā)送時會回調(diào)該方法,可以在該方法執(zhí)行自定義的發(fā)送邏輯或者打印發(fā)送日志
  • postAfterHttpResponseBodyString:  Http請求響應(yīng)后,對響應(yīng)body字符串進行進行后置處理,比如如果是加密數(shù)據(jù)可以進行解密
  • postAfterHttpResponseBodyResult:  Http請求響應(yīng)后,對響應(yīng)body反序列化后的對象進行后置處理,比如填充默認(rèn)返回值
  • postAfterMethodReturnValue:   Http請求響應(yīng)后,對代理的方法的返回值進行后置處理,類似aop的后置處理
回調(diào)參數(shù)說明:
  • HttpMetadata: 表示此次Http請求的請求體,包含請求url,請求頭、請求方式、請求cookie、請求體、請求參數(shù)等等。
  • HttpApiMethodInvocation: 繼承自MethodInvocation, 表示被代理的方法調(diào)用上下文,可以拿到被代理的類,被代理的方法,被代理的HttpAPI注解、HttpInterface注解等信息

3.7、配置自定義的Http客戶端

默認(rèn)使用的是Okhttp客戶端,如果要重新配置Okhttp客戶端,注入spring的bean即可,如下

@Configuration
public class CusotmConfiguration {

    @Bean
    public OkHttpClient myOHttpClient(){
        return new OkHttpClient.Builder()
                .readTimeout(50, TimeUnit.SECONDS)
                .writeTimeout(50, TimeUnit.SECONDS)
                .connectTimeout(10, TimeUnit.SECONDS)
                .connectionPool(new ConnectionPool(20,10, TimeUnit.MINUTES))
                .build();
    }
}

4、企業(yè)級渠道對接實戰(zhàn)

案例背景:

假設(shè)現(xiàn)在需要對接一個某天氣服務(wù)的所有接口,需要在請求cookie帶上一個token字段和sessionId字段,這兩個字段的值需要每次接口調(diào)用前先手動調(diào)渠道方的一個特定的接口申請獲取,token值在該接口返回值中返回,sessionId在該接口的響應(yīng)頭中返回。

然后還需要在請求頭上帶上一個sign簽名字段, 該sign簽名字段生成規(guī)則需要用渠道方提供的公鑰對所有請求體和請求參數(shù)進行加簽生成。

然后還需要在每個接口的查詢參數(shù)上都帶上一個渠道方分配的客戶端appId。

4.1、在application.yml中配置對接渠道方的信息

channel:
  mtuan:
    # 請求域名
    url: http://127.0.0.1:8999
    # 分配的渠道appId
    appId: UUU-asd-01
    # 分配的公鑰
    publicKey: fajdkf9492304jklfahqq

4.2、自定義該渠道方的HttpAPI注解

假設(shè)現(xiàn)在對接的是某團,所以自定義注解叫@MTuanHttpApi吧,然后需要在該注解上標(biāo)記@HttpApi注解,并且需要配置processor字段,需要去自定義實現(xiàn)一個HttpApiProcessor這個具體實現(xiàn)后續(xù)講。

有了這個注解后就可以自定義該注解與對接渠道方相關(guān)的各種字段配置,當(dāng)然也可以不定義。

注意這里url的字段是使用 @AliasFor(annotation = HttpApi.class),這樣構(gòu)建的HttpMetadata中會默認(rèn)解析填充要請求體,不標(biāo)記則也可自行處理。

@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@HttpApi(processor = MTuanHttpApiProcessor.class)
public @interface MTuanHttpApi {

    /**
     * 渠道方域名地址
     */
    @AliasFor(annotation = HttpApi.class)
    String url() default "${channel.mtuan.url}";

    /**
     * 渠道方分配的appId
     */
    String appId() default "${channel.mtuan.appId}";
}
@Slf4j
@Component
public class MTuanHttpApiProcessor implements HttpApiProcessor<MTuanHttpApi> {
    
}

注意實現(xiàn)的HttpApiProcessor泛型要指定為剛才定義的注解@MTuanHttpApi類型,因為這個HttpApiProcessor配置到它上面,如果需要通用處理可以定義為Annocation類型

4.3、對接接口

有了@MTuanHttpApi注解之后就可以開始對接接口了,比如假設(shè)有兩個接口要對接。一個就是前面說的獲取令牌的接口。一個是獲取天氣情況的接口。

為什么getToken方法返回值是 HttpResponse,這是UniHttp內(nèi)置的原始Http響應(yīng)對象,方便我們?nèi)ツ玫皆糎ttp響應(yīng)體的一些內(nèi)容(比如響應(yīng)狀態(tài)碼、響應(yīng)cookie)。

其中的泛型BaseRsp才是實際的Http響應(yīng)體反序列化后的內(nèi)容。而getCityWeather方法沒有使用HttpResponse包裝,BaseRsp只是單純Http響應(yīng)體反序列化后的內(nèi)容,這是兩者的區(qū)別。

前面介紹過 HttpResponse,其實大部份接口是不關(guān)注HttpResponse的可以不用去配置。

@MTuanHttpApi
public interface WeatherApi {
    
    /**
     * 根據(jù)城市名獲取天氣情況
     */
    @GetHttpInterface("/getCityByName")
    BaseRsp<WeatherDTO> getCityWeather(@QueryPar("city") String cityName);

    /**
     *  根據(jù)appId和公鑰獲取令牌
     */
    @PostHttpInterface("/getToken")
    HttpResponse<BaseRsp<TokenDTO>> getToken(@HeaderPar("appId") String appId, @HeaderPar("publicKey")String publicKey);

}

4.4、自定義HttpApiProcessor

在之前我們自定義了一個@MTuanHttpApi注解上指定了一個MTuanHttpApiProcessor,接下來我們?nèi)崿F(xiàn)他的具體內(nèi)容為了實現(xiàn)我們案例背景里描述的功能。

@Slf4j
@Component
public class MTuanHttpApiProcessor implements HttpApiProcessor<MTuanHttpApi> {

    /**
     *  渠道方分配的公鑰
     */
    @Value("${channel.mtuan.publicKey}")
    private String publicKey;

    @Value("${channel.mtuan.appId}")
    private String appId;

    @Autowired
    private Environment environment;
    
    @Autowired
    private WeatherApi weatherApi;

    /** 實現(xiàn)-postBeforeHttpMetadata: 發(fā)送Http請求之前會回調(diào)該方法,可對Http請求體的內(nèi)容進行二次處理
     *
     * @param httpMetadata              原來的請求體
     * @param methodInvocation          被代理的方法
     * @return                          新的請求體
     */
    @Override
    public HttpMetadata postBeforeHttpMetadata(HttpMetadata httpMetadata, HttpApiMethodInvocation<MTuanHttpApi> methodInvocation) {
        /**
         * 在查詢參數(shù)中添加提供的appId字段
         */
        // 獲取MTuanHttpApi注解
        MTuanHttpApi apiAnnotation = methodInvocation.getProxyApiAnnotation();

        // 獲取MTuanHttpApi注解的appId,由于該appId是環(huán)境變量所以我們從environment中解析取出來
        String appIdVar = apiAnnotation.appId();
        appIdVar = environment.resolvePlaceholders(appIdVar);

        // 添加到查詢參數(shù)中
        httpMetadata.putQueryParam("appId",appIdVar);

        /**
         *  生成簽名sign字段
         */
        // 獲取所有查詢參數(shù)
        Map<String, Object> queryParam = httpMetadata.getHttpUrl().getQueryParam();

        // 獲取請求體參數(shù)
        HttpBody body = httpMetadata.getBody();

        // 生成簽名
        String signKey = createSignKey(queryParam,body);

        // 將簽名添加到請求頭中
        httpMetadata.putHeader("sign",signKey);

        return httpMetadata;
    }

    private String createSignKey(Map<String, Object> queryParam, HttpBody body) {
        // todo 偽代碼
        // 1、將查詢參數(shù)拼接成字符串
        String queryParamString = queryParam.entrySet()
                .stream().map(e -> e.getKey() + "="+e.getValue())
                .collect(Collectors.joining(";"));

        // 2、將請求體參數(shù)拼接成字符串
        String bodyString = "";
        if (body instanceof HttpBodyJSON){
            // application/json  類型的請求體
            bodyString = body.toStringBody();
        }else if (body instanceof HttpBodyFormData){
            // application/x-www-form-urlencoded 類型的請求體
            bodyString = body.toStringBody();
        }else if (body instanceof HttpBodyMultipart){
            // multipart/form-data 類型的請求體
            bodyString =  body.toStringBody();
        }

        // 使用公鑰publicKey 加密拼接起來
        String sign = publicKey + queryParamString + bodyString;
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] digest = md.digest(sign.getBytes());
            return new String(digest);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     *  實現(xiàn)-postBeforeHttpMetadata: 發(fā)送Http請求時,可定義發(fā)送請求的行為 或者打印請求和響應(yīng)日志。
     */
    @Override
    public HttpResponse<?> postSendHttpRequest(HttpSender httpSender, HttpMetadata httpMetadata) {
        //  忽略 weatherApi.getToken的方法回調(diào),否則該方法也會回調(diào)此方法會遞歸死循環(huán)。 或者該接口指定自定義的HttpApiProcessor重寫postSendingHttpRequest
        Method getTokenMethod = ReflectionUtils.findMethod(WeatherServiceApi.class, "getToken",String.class,String.class);
        if (getTokenMethod == null || getTokenMethod.equals(methodInvocation.getMethod())){
            return httpSender.sendHttpRequest(httpMetadata);
        }
        
        // 1、動態(tài)獲取token和sessionId
        HttpResponse<String> httpResponse = weatherApi.getToken(appId, publicKey);

        // 從響應(yīng)體獲取令牌token
        String token = httpResponse.getBodyResult();
        // 從響應(yīng)頭中獲取sessionId
        String sessionId = httpResponse.getHeader("sessionId");

        // 把這兩個值放到此次的請求cookie中
        httpMetadata.addCookie(new Cookie("token",token));
        httpMetadata.addCookie(new Cookie("sessionId",sessionId));
        
        log.info("開始發(fā)送Http請求 請求接口:{} 請求體:{}",httpMetadata.getHttpUrl().toUrl(),httpMetadata.toHttpProtocol());

        // 使用框架內(nèi)置工具實現(xiàn)發(fā)送請求
        HttpResponse<?> rsp =  httpSender.sendHttpRequest(httpMetadata);

        log.info("開始發(fā)送Http請求 響應(yīng)結(jié)果:{}",rsp.toHttpProtocol());
        
        return rsp;
    }

    /**
     *  實現(xiàn)-postAfterHttpResponseBodyResult: 反序列化后Http響應(yīng)體的內(nèi)容后回調(diào),可對該結(jié)果進行二次處理返回
     * @param bodyResult                     Http響應(yīng)體反序列化后的結(jié)果
     * @param rsp                            原始Http響應(yīng)對象
     * @param method                         被代理的方法
     * @param httpMetadata                   Http請求體
     */
    @Override
    public Object postAfterHttpResponseBodyResult(Object bodyResult, HttpResponse<?> rsp, Method method, HttpMetadata httpMetadata) {
        if (bodyResult instanceof BaseRsp){
            BaseRsp baseRsp = (BaseRsp) bodyResult;
            // 設(shè)置
            baseRsp.setCode(999);
        }
        
        return bodyResult;
    }
}

上面我們分別重寫了postBeforeHttpMetadata、postSendHttpRequest、postAfterHttpResponseBodyResult三個生命周期的鉤子方法去完成我們的需求,在發(fā)送請求前對請求體進行加簽、在發(fā)送請求時動態(tài)獲取令牌重新構(gòu)建請求體和打印日志、在發(fā)送請求后給響應(yīng)對象設(shè)置code為999。

責(zé)任編輯:武曉燕 來源: 一安未來
相關(guān)推薦

2025-05-06 00:12:10

2020-12-17 07:59:46

聲明式代碼命令式代碼代碼

2009-06-22 09:01:57

Spring聲明式事務(wù)

2022-06-21 08:12:17

K8sAPI對象Kubernetes

2024-11-13 19:03:14

2013-06-27 09:31:37

聲明式編程命令式編程編程

2009-09-02 14:18:08

C#聲明COM接口

2020-09-04 06:27:22

編碼命令式聲明式代碼

2021-09-06 13:42:14

Spring聲明式事務(wù)

2024-02-28 08:37:28

Lambda表達式Java函數(shù)式接口

2009-09-02 14:26:50

C#對接口成員訪問

2014-10-30 18:44:45

暢捷通T+平臺

2023-08-30 13:22:00

測試框架工具

2025-01-16 08:45:48

2012-03-15 11:21:19

Java

2009-07-07 17:32:31

HTTP Servle

2009-09-01 10:49:28

C#具有隱式類型聲明

2010-05-26 13:56:59

Tomcat 7Servlet 3.0

2022-08-23 16:07:02

ArkUI鴻蒙

2019-07-04 15:13:16

分布式緩存Redis
點贊
收藏

51CTO技術(shù)棧公眾號

国产99视频在线| 黄色精品视频在线观看| 亚洲同志男男gay1069网站| 久久一夜天堂av一区二区三区| 国产91色在线| 久久久精品少妇| 国产一区在线电影| 欧美午夜精品免费| 国产精品视频一二三四区| 日韩精品视频在线观看一区二区三区| 久久综合影视| 久久91亚洲人成电影网站| 欧美老熟妇乱大交xxxxx| 日韩综合av| 黑人欧美xxxx| mm131午夜| 韩国精品视频| 成人午夜看片网址| 国产日韩欧美在线视频观看| 一级片免费网址| 亚洲国产精品91| 亚洲天堂第一页| 亚洲av成人片无码| 国产成人免费av一区二区午夜| 日韩欧美在线第一页| a天堂资源在线观看| 在线观看免费黄色| 久久久影视传媒| 成人动漫在线视频| 一区二区美女视频| 日日夜夜一区二区| 69视频在线免费观看| 婷婷伊人五月天| 欧美美女视频| 亚洲嫩模很污视频| 国产精品久久AV无码| 欧美黄色一级| 欧美精品777| 国产一区二区在线免费播放| 成人私拍视频| 色94色欧美sute亚洲13| 黄在线观看网站| 人狥杂交一区欧美二区| 午夜日韩在线观看| 91黄色在线看| 爱看av在线| 亚洲成av人影院| 97视频在线免费| 久久五月精品中文字幕| 亚洲一区二区三区四区不卡| 老司机午夜免费福利视频| 国内精品久久久久国产| 136国产福利精品导航| 宅男一区二区三区| 麻豆传媒在线免费看| 国产精品久久久久久久久免费丝袜 | 福利视频一区| 欧美系列一区二区| 黄色aaa级片| 成人在线中文| 欧美精品九九99久久| aaa一级黄色片| 视频一区日韩精品| 欧美精品一区二区久久婷婷| 白嫩情侣偷拍呻吟刺激| 欧美交a欧美精品喷水| 亚洲精品日韩丝袜精品| av男人的天堂av| 久久美女精品| 欧美伦理91i| 国产做受高潮漫动| 亚洲免费在线| 国产精品三级网站| 一区二区三区黄| 国产激情偷乱视频一区二区三区| 98国产高清一区| 日韩中文字幕观看| 久久精品夜色噜噜亚洲aⅴ| 日韩中文字幕一区二区| 蜜桃视频在线观看免费视频网站www| 亚洲三级电影网站| a级黄色小视频| 欧洲av不卡| 欧美一级黄色大片| aaaaa级少妇高潮大片免费看| 欧美日韩黑人| 欧美激情免费看| www.日韩一区| 国产成人精品亚洲日本在线桃色| 久久国产精品久久| 蜜桃视频在线观看www社区| 亚洲一区日韩精品中文字幕| 国产av无码专区亚洲精品| 欧美成人xxxx| 日韩精品极品视频免费观看| 国产精品无码无卡无需播放器| 亚洲美女视频| 国产成人精品久久二区二区91| 国产精品无码白浆高潮| av日韩在线网站| 亚洲在线视频一区二区| mm视频在线视频| 欧美剧情电影在线观看完整版免费励志电影| wwwxxx色| 欧美激情黄色片| 555www成人网| 午夜久久久久久久久久| 国产欧美日韩激情| 亚洲精品蜜桃久久久久久| 久久久免费人体| 日韩精品中文字幕有码专区 | 99久久国产综合精品成人影院| 国外成人免费在线播放 | 亚洲精品在线观看视频| 青青青视频在线播放| 国产精品久久国产愉拍| 999国产在线| 18视频免费网址在线观看| 欧美日韩亚洲系列| 色诱av手机版| 66久久国产| 国产一区二区在线免费| 番号集在线观看| 午夜av区久久| www.美色吧.com| 一本一道久久综合狠狠老| 国产精品久久婷婷六月丁香| 视频一区二区在线播放| 亚洲一区二区三区中文字幕在线 | 成人夜色视频网站在线观看| 免费观看中文字幕| 日本免费成人| 中文字幕亚洲一区在线观看| 国模精品一区二区三区| 一道本在线视频| 成人羞羞视频在线看网址| 久久久久久久97| 精品国产无码一区二区| 亚洲天堂精品视频| 亚洲欧洲日本精品| 成人在线免费观看网站| 国产激情综合五月久久| 成人在线免费公开观看视频| 日韩欧美在线字幕| 自拍偷拍中文字幕| 亚洲欧美日韩精品一区二区| 好看的日韩精品视频在线| 国产极品在线观看| 亚洲成年人在线| 日韩美女视频网站| 91在线精品一区二区| 阿v天堂2018| 女人抽搐喷水高潮国产精品| 91产国在线观看动作片喷水| 日韩a在线观看| 欧美日韩国产在线看| 蜜桃精品成人影片| 久久久久在线| 先锋影音亚洲资源| 亚洲青青久久| 美日韩在线视频| 成人无码一区二区三区| 亚洲成人激情自拍| 中文字幕日韩三级片| 美女黄色成人网| 亚洲国产欧美一区二区三区不卡| 91另类视频| 久久国产精品久久国产精品| 欧美熟妇交换久久久久久分类 | 中文字幕第四页| 国产视频一区二区在线观看| 无尽裸体动漫2d在线观看| 91精品一区二区三区综合在线爱| 99国产视频| 天堂√中文最新版在线| 国产亚洲人成网站在线观看| 91成人国产综合久久精品| 亚洲精选免费视频| 老熟妇精品一区二区三区| 日韩激情av在线| 黄色一级片av| 久久成人高清| 亚洲一区二区三区视频| 僵尸再翻生在线观看| 在线成人中文字幕| 99热这里只有精品9| 午夜精品福利在线| 五月天精品在线| 成人少妇影院yyyy| 国产裸体免费无遮挡| 欧美成人国产| 欧洲一区二区在线观看| 日韩三级av高清片| 日韩美女免费观看| av毛片在线播放| 亚洲欧美日韩中文在线制服| 国产女人18毛片18精品| 精品福利在线视频| www.com.av| 2020日本不卡一区二区视频| 国内av一区二区| 久久精品三级| 加勒比成人在线| 日韩一区二区在线| 精品日本一区二区三区| 成人污污www网站免费丝瓜| 欧美一级淫片播放口| 中中文字幕av在线| 一本色道久久88精品综合| 亚洲黄色在线观看视频| 欧美性猛交一区二区三区精品| 久久精品国产亚洲av高清色欲 | 亚洲精品国产美女| 国产精品欧美激情在线| 91豆麻精品91久久久久久| 欧美黄色一区二区三区| 国产精品夫妻自拍| 国精品无码人妻一区二区三区| 国产成人自拍网| 午夜免费看毛片| 日本一区中文字幕| 人人妻人人添人人爽欧美一区| 亚洲综合婷婷| 亚洲一区在线免费| 日本一区二区免费高清| 欧美久久久久久| 台湾色综合娱乐中文网| 成人av蜜桃| 日本免费精品| 3d动漫啪啪精品一区二区免费 | 国产精品久久久久毛片大屁完整版| 一区二区三区四区免费观看| 成人在线免费小视频| 日韩av电影免费播放| 亚洲va久久| 欧美日韩国产免费一区二区三区 | 久久久人成影片一区二区三区在哪下载| 欧美日韩国产成人在线观看| av在线免费网站| 欧美成人激情在线| 超碰在线免费播放| 久久精品国产久精国产一老狼| 9色在线观看| 日韩视频欧美视频| 日本电影全部在线观看网站视频 | 免费影院在线观看一区| 欧美尿孔扩张虐视频| 国产一区视频观看| 日韩欧美在线精品| 久久免费一区| 国产一区2区| 婷婷久久青草热一区二区 | 国产成人一二三区| 欧美在线资源| 久久艹国产精品| 亚洲免费高清| 熟妇人妻va精品中文字幕| 爽好久久久欧美精品| 欧美伦理片在线观看| 久久精品国产亚洲aⅴ| 波多野结衣免费观看| 国产91丝袜在线18| 玖玖爱在线精品视频| 91麻豆精东视频| 一级片黄色录像| 亚洲女性喷水在线观看一区| 国产一级一级片| 狠狠躁夜夜躁人人爽天天天天97| 日本中文字幕在线观看视频| 欧美日韩高清一区二区不卡| 国产毛片久久久久| 亚洲第一精品福利| 你懂的免费在线观看| 中文字幕在线看视频国产欧美| 黄色网在线看| 97视频在线观看免费| 国产成人免费9x9x人网站视频| 国产欧美日韩中文字幕| 51vv免费精品视频一区二区| 欧美午夜精品理论片a级大开眼界 欧美午夜精品久久久久免费视 | 久久精选视频| 亚洲综合伊人久久| av色综合久久天堂av综合| 免费成人深夜天涯网站| 亚洲精品免费看| 国产精品第5页| 欧美精品18+| 日本一二三区在线视频| 久久精品成人动漫| 手机av在线| 91美女片黄在线观看游戏| 奇米777国产一区国产二区| 亚洲人成人77777线观看| 精品动漫一区| 视频免费1区二区三区| 99久久综合精品| 亚洲波多野结衣| 一本久道久久综合中文字幕| 国产草草影院ccyycom| 一本久久综合亚洲鲁鲁| 国产高清中文字幕在线| 91最新国产视频| 精品国产乱码久久久久久果冻传媒 | 欧美在线日韩精品| 欧美日本三区| 日韩爱爱小视频| 91在线精品秘密一区二区| 在线免费观看亚洲视频| 色狠狠一区二区| 人妻va精品va欧美va| 久久久电影免费观看完整版| 超碰国产一区| 韩国一区二区三区美女美女秀| 99久久综合| 九九视频精品在线观看| 北条麻妃一区二区三区| 久久高清内射无套| 欧美艳星brazzers| 四虎影视精品成人| 久久久日本电影| 日韩第一区第二区| 一区不卡视频| 蜜桃视频第一区免费观看| 国产高清自拍视频| 亚洲一区二区三区视频在线| 国产精品高潮呻吟AV无码| 一区二区三区国产在线观看| 九色porny视频在线观看| 国产精品对白刺激久久久| 亚洲精品国产首次亮相| 亚洲欧美日本一区二区三区| 亚洲国产高清aⅴ视频| 欧美一区二区三区久久久| 日韩av网站在线| 欧美办公室脚交xxxx| 国产综合 伊人色| 91久久综合| 五月天激情小说| 天天综合天天综合色| 少妇人妻偷人精品一区二区| 久久久亚洲天堂| 精品伊人久久久| 五十路熟女丰满大屁股| 91在线小视频| 天堂网中文字幕| 国产一区二区成人| 日韩色淫视频| 在线免费观看成人| 国内精品视频一区二区三区八戒| 天天做夜夜爱爱爱| 欧美一级日韩一级| 色呦呦呦在线观看| 国产精品免费观看高清| 亚洲精品系列| www.免费av| 在线看不卡av| 午夜在线视频| 91超碰在线免费观看| 亚洲第一伊人| 一区二区不卡免费视频| 日本久久一区二区| 午夜免费播放观看在线视频| 亚洲mm色国产网站| 精品福利av| 久久久久亚洲av无码a片| 欧美日韩一区二区在线观看| 免费黄网在线观看| 91福利入口| 亚洲自拍另类| 美国黄色特级片| 欧美成人官网二区| 午夜影院在线播放| 亚洲综合首页| 成人av第一页| 国产一级片一区二区| 乱亲女秽乱长久久久| 免费看久久久| 制服丝袜综合网| 亚洲午夜久久久久久久久电影院| 日本wwwxxxx| 国产精品福利网站| 很黄很黄激情成人| 无码人妻精品一区二区中文| 777欧美精品| 丝袜诱惑一区二区| 国产精品h视频| 91亚洲永久精品| 国产又粗又长又大视频| 97精品视频在线| 99精品视频精品精品视频 | 啄木系列成人av电影| 天堂av8在线| 疯狂做受xxxx高潮欧美日本 | 91精品国产91久久| 99久久夜色精品国产亚洲1000部| 好吊色视频一区二区三区| 欧美日韩高清一区二区三区| 色是在线视频| 少妇久久久久久被弄到高潮| 国产欧美中文在线|