{"id":18810003,"url":"https://github.com/vizaizai/easy-http","last_synced_at":"2025-04-13T20:29:41.557Z","repository":{"id":39909317,"uuid":"283991976","full_name":"vizaizai/easy-http","owner":"vizaizai","description":"一个基于注解和接口的http客户端，使用更简单，更方便","archived":false,"fork":false,"pushed_at":"2023-05-09T09:17:06.000Z","size":300,"stargazers_count":8,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2023-07-26T22:10:33.116Z","etag":null,"topics":["http-client","java","tool"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vizaizai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-07-31T09:09:55.000Z","updated_at":"2023-03-21T08:04:19.000Z","dependencies_parsed_at":"2022-09-26T22:10:33.413Z","dependency_job_id":null,"html_url":"https://github.com/vizaizai/easy-http","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vizaizai%2Feasy-http","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vizaizai%2Feasy-http/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vizaizai%2Feasy-http/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vizaizai%2Feasy-http/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vizaizai","download_url":"https://codeload.github.com/vizaizai/easy-http/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223602938,"owners_count":17172006,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["http-client","java","tool"],"created_at":"2024-11-07T23:18:29.502Z","updated_at":"2024-11-07T23:18:30.042Z","avatar_url":"https://github.com/vizaizai.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"#### easy-http\n\n##### 快速开始\n\n\u003e easy-http是一个完全基于注解和接口的http客户端，为简化开发、提高效率而生。\n\n##### 1. 特性\n\n   + 注解简单： 遵循大众的命名习惯，@Body、@Param、@Var等注解见名之意。\n   + 无侵入： 接口不需要继承。\n   + 请求体支持x-www-form-urlencoded、form-data（包含文件）、binary(二进制)、raw(json、xml等文本)\n   + 多客户端实现: 底层支持多种客户端，默认已实现Java原生URL和HttpClient，也可自定义客户端。\n   + 支持异步请求。\n   + 支持自定义编解码：默认已经内置了JSON编解码(返回参数支持泛型)，如需支持xml，可自定义。\n   + 支持自定义拦截器：请求前，和请求后的拦截。拦截器可满足大部分业务需求，如：计算请求耗时，动态添加公共请求头，返回错误统一处理等等。\n   + 支持请求重试，可自定义重试触发规则。\n   + 提供spring-boot版本，使用更简单。\n\n##### 2. 安装\n\nJava版本: 最低 `8`\n\n   ``` xml\n   \u003cdependency\u003e\n     \u003cgroupId\u003ecom.github.vizaizai\u003c/groupId\u003e\n     \u003cartifactId\u003eeasy-http\u003c/artifactId\u003e\n     \u003cversion\u003e最新版\u003c/version\u003e\n   \u003c/dependency\u003e\n   ```\n\nspring-boot版本移步: [easy-http-boot-starter](https://github.com/vizaizai/easy-http-spring)\n\n##### 3. 使用\n\n   首先定义一个接口:\n\n   ``` java\n   public interface BookHttpService {\n       @Get(\"/books/{id}\")\n       ApiResult\u003cBook\u003e getBookById(@Var(\"id\") String id);\n   }    \n   ```\n\n   这是一个最简单的查询接口，然后通过接口构建执行\n\n   ``` java\n   BookHttpService bookHttpService = EasyHttp.builder()\n                      .url(\"127.0.0.1:8888\")\n                      .build(BookHttpService.class);\n   ApiResult\u003cBook\u003e bookRet = bookHttpService.getBookById(\"166895\");\n   System.out.println(bookRet.getData().getName());\n   ```\n\n   像类似@GET的请求方法注解还有@Post、@Put、@Delete。\n\n##### 4.方法参数注解\n\n\u003e 基础类型定义：基本数据类型+ 包装类型 + void + Void +String + Number + Number实现类\n\n   + @var\n\n     路径变量注解，用于替换路径上的变量，路径变量只能是基础类型参数。\n\n     ```java\n     @Get(\"/books/{id}\")\n     ApiResult\u003cBook\u003e getBookById(@Var(\"id\") String id);\n     @Get(\"/books?author={author}\")\n     ApiResult\u003cBook\u003e getBookById(@Var(\"author\") String author);\n     ```\n\n   + @Param\n\n     被注解的参数可以是基础类型、数组、列表、Map 和 JavaBean，注意：\n\n     \t- 如果被注解的参数是基础类型，那么value查询参数的key。\n     \t- 如没有指定value并且项目编译时设置了`-parameters`，则key会取被注解字段的名称，否则为arg1~n。\n     \t- 当一个方法参数上没有任何注解时默认为@Param。\n     \t- 当请求方式是`GET`时，@Param参数固定为查询参数(拼接url)，否则默认为`x-www-form-urlencoded`(表单)\n\n     ``` java\n     @Get(\"/books\")\n     ApiResult\u003cList\u003cBook\u003e\u003e listBooksByAuthor1(@Param(\"author\") String author);\n     \n     // 设置了-parameters\n     @Get(\"/books\")\n     ApiResult\u003cList\u003cBook\u003e\u003e listBooksByAuthor2(@Param String author);\n     \n     @Get(\"/books\")\n     ApiResult\u003cList\u003cBook\u003e\u003e listBooksByAuthor(@Param Map\u003cString, String\u003e params);\n     \n     @Get(\"/books\")\n     ApiResult\u003cList\u003cBook\u003e\u003e listBooksByAuthor(Map\u003cString, String\u003e params);\n     \n     @Get(\"/books\")\n     ApiResult\u003cList\u003cBook\u003e\u003e listBooksByIds(@Param(\"ids\") List\u003cString\u003e ids);\n     \n     @Post(\"/addBookUseForm\")\n     String test5(@Param Book book); // 请求体x-www-form-urlencoded\n     \n     @POST(value=\"/addBookUseForm\", bodyType = RequestBodyType.NONE) // 指定无请求体，参数拼接到url上面\n     String test5_1(@Param Book book); // 拼接url，如 /addBookUseForm?name=easyhttp\u0026author=lcw\n     ```\n\n   + @Body\n\n     包含请求体的内容。\n\n     - 当被注解的参数类型是`FormData`, 则请求体为`multipart/form-data`。`FormData`可添加文本和文件。\n     - 当被注解参数类型为`BodyContent`的实现类时，请求体为所有二进制文件。`BodyContent`默认已实现`FileContent`、`InputStreamContent`和`StringContent`。\n     - 否则被注解的参数会根据编码器处理放到请求体里, 如果被注解的参数是基础类型，则直接转化成字符传后放入请求体中。\n\n``` java\n@Post(\"/books\")\nvoid addBook(@Body Book book);\n\n@Post(\"/addBookUseJSON\")\nString test6(@Body Book1 book1);\n\n@Post(\"/addBookUseJSON\")\nString test6_1(@Body Map\u003cString,Object\u003e book);\n\n@Post(\"/addBookUseJSON\")\nString test6_2(@Body String content);\n\n\n@Post(\"/addBookUseFormData\")\nString test8(@Body FormData formData);\n// form-data 的使用\nFormData formData = new FormData();\nformData.addText(\"author\",\"吴承恩\");\nformData.addText(\"name\",\"西游记\");\nformData.addText(\"lang\",\"chinese\");\nformData.addFile(\"files\", new File(\"C:\\\\Users\\\\dell\\\\Desktop\\\\logo.png\"));\nformData.addFile(\"files\", new File(\"C:\\\\Users\\\\dell\\\\Desktop\\\\Dingtalk_20210317145859.jpg\"));\nformData.addFile(\"files\", new File(\"C:\\\\Users\\\\dell\\\\Desktop\\\\jsd_pro_back.rar\"));\nparamService.test8(formData);\n\n@Post(\"/upload/e-book/{id}\")\nString test9(@Var String id, @Body BodyContent bodyContent);\n// 二进制文件的使用\nparamService.test9(\"123\", FileContent.of(new File(\"C:\\\\Users\\\\dell\\\\Desktop\\\\jsd_pro_back.rar\")));\n\n```\n\n   + @Headers\n\n     请求头注解，可用于接口、方法和方法参数上，当用于接口和方法需指定value, 格式key:  value (冒号后面有和空格)\n\n     ``` java\n     @Headers({\"clent: Easy-http\"})\n     @Post(\"/books\")\n     ApiResult\u003cVoid\u003e addBook(@Body Book book,  @Headers Map\u003cString, String\u003e headers);\n     ```\n\n##### 5. 自定义编码器\n\n\u003e 编码器： 将参数对象解析成http的相关请求参数\n\n编写自定义编码器类`CustomEncoder`实现`Encoder`接口\n\n``` java\npublic class CustomEncoder implements Encoder {\n    /**\n     * 将对象转化成Body（如果参数类型本身为基础类型，则直接转化成string），用于编码 @Body注解的对象（默认jackson编码）\n     * @param object 待编码对象\n     * @param bodyType 请求体对象类型\n     * @return Body\n     */\n    @Override\n    public Body encode(Object object, Type bodyType) {\n        return null;\n    }\n}\n```\n\n在构建对象是加入`CustomEncoder`\n\n``` java\nBookHttpService bookHttpService = EasyHttp.builder()\n                                            .url(\"127.0.0.1:8888\")\n                                            .encoder(new CustomEncoder())\n                                            .build(BookHttpService.class);\n```\n\n##### 6. 自定义解码器\n\n\u003e 将返回体解析成对象\n\n编写自定义编码器类`CustomDecoder`实现`Decoder`接口\n\n``` java\npublic class CustomDecoder implements Decoder {\n    /**\n     * 响应解码(默认实现jackson解码)\n     * @param response 响应参数\n     * @param type 返回值类型\n     * @return Object\n     */\n    @Override\n    public Object decode(HttpResponse response, Type type) {\n        return null;\n    }\n}\n```\n在构建对象是加入`CustomDecoder`\n\n``` java\nBookHttpService bookHttpService = EasyHttp.builder()\n                                        .url(\"127.0.0.1:8888\")\n                                        .encoder(new CustomEncoder())\n                                        .decoder(new CustomDecoder())\n                                        .build(BookHttpService.class);\n```\n##### 7. 自定义拦截器\n\n   \u003e 在请求发出前和请求响应后进行拦截\n\n编写自定义编码器类`ResultInterceptor`实现`HttpInterceptor`接口，抽离data部分返回\n\n``` java\npublic class ResultInterceptor implements HttpInterceptor {\n    @Override\n    public boolean preHandle(HttpRequest request) {\n        return true;\n    }\n\n    @Override\n    public void postHandle(HttpRequest request, HttpResponse response) {\n         if (!response.isOk()) {\n            throw new EasyHttpException(\"请求错误~\");\n        }\n        if (response.getBody() == null) {\n           return;\n        }\n\n        try {\n            JavaType javaType = mapper.getTypeFactory().constructParametricType(ApiResult.class,\n                    mapper.getTypeFactory().constructType(response.getReturnType()));\n            ApiResult\u003cObject\u003e bizRet = mapper.readValue(response.getBody().asInputStream(), javaType);\n\n            // 假设业务code：200 为操作成功\n            if (bizRet.getCode() == 200) {\n                if (bizRet.getData() != null) {\n                    // 取data作为返回值\n                    response.setReturnObject(bizRet.getData());\n                    return;\n                }\n            }\n            response.setReturnObject(null);\n        }catch (Exception e) {\n            throw new EasyHttpException(e);\n        }\n    }\n\n    @Override\n    public int order() {\n        return 4;\n    }\n    @Override\n    public List\u003cExcludePath\u003e excludes() {\n        return Arrays.asList(ExcludePath.instance(\"/books/**\", HttpMethod.DELETE, HttpMethod.POST));\n    }\n}\n```\n\n`preHandle` 请求前拦截，返回true则通过，反之则被拦截。`postHandle` 响应后拦截。`order`定义拦截器的顺序，值越小，越靠前。`excludes`定义需要排除使用拦截器的路径列表。这里`ResultInterceptor`对统一的返回作了处理。不仅判断了请求和业务是否成功，并且还统一包装了返回体，去掉了通过返回部分，具体根据业务定制。\n\n在构建对象是加入拦截器列表\n\n``` java\n        BookHttpService bookHttpService = EasyHttp.builder()\n                                                    .url(\"127.0.0.1:8888\")\n                                                    .encoder(new CustomEncoder())\n                                                    .decoder(new CustomDecoder())\n                                                    .withInterceptor(new ResultInterceptor())\n                                                    .withInterceptor(new TimeInterceptor())\n                                                    .build(BookHttpService.class);\n```\n##### 8. 切换客户端\n\n   ```java\n    EasyHttp.builder()\n            .url(\"127.0.0.1:8888\")\n            .client(ApacheHttpClient.getInstance())\n            .build(BookHttpService.class);\n   ```\n##### 9. 异步请求\n\n将方法的返回参数设为`Future`或者`CompletableFuture` , 就可以轻松实现异步。\n\n```java\n// 接口方法\n@Get(\"/books\")\nCompletableFuture\u003cApiResult\u003cList\u003cBook\u003e\u003e\u003e foo();\n\n// 执行异步请求\nCompletableFuture\u003cApiResult\u003cList\u003cBook\u003e\u003e\u003e foo = bookHttpService.foo();\nfoo.thenAccept(e-\u003eSystem.out.println(e.getData()))\n   .thenRun(()-\u003eSystem.out.println(\"异步请求执行完毕\"));\nSystem.out.println(\"异步\");\nfoo.join();\n```\n\n\u003e 有关Java8`CompletableFuture`的更多操作，请前往 [Java8 CompletableFuture](https://blog.csdn.net/lcw158852/article/details/107981506)\n\n##### 10. 重试\n\n可以全局开启重试，也可以在请求方式注解上针对每一个请求设置重试。\n\n触发规则：默认规则为`当请求方式为GET并且HTTP状态码为5XX时`或者`当连接超时时`,支持自定义触发规则 `retryable(Integer retries, Integer interval, RetryTrigger retryTrigger)`, 实现RetryTrigger接口传入即可。\n\n``` java\nEasyHttp.builder()\n        .url(\"127.0.0.1:8888\")\n        .client(DefaultURLClient.getInstance())\n        .retryable(3,1000,new DefaultRule())\n        .build(BookHttpService.class);\n```\n\n##### 11. 文件下载\n\neasyHttp支持直接返回`HttpResponse`类型，可以拿到响应字节流和响应头。\n\n#### 联系作者\n\n如您有好的建议，或者有任何疑问，可联系我\n\n- QQ: 274550900\n- Email: liaochongwei666@163.com","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvizaizai%2Feasy-http","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvizaizai%2Feasy-http","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvizaizai%2Feasy-http/lists"}