Solon v3.0.3

solon-net-httputils

</> markdown
<dependency>
    <groupId>org.noear</groupId>
    <artifactId>solon-net-httputils</artifactId>
</dependency>

1、描述

网络扩展插件。提供基础的 http 调用。默认基于 HttpURLConnection 适配,当有 okhttp 引入时自动切换为 okhttp 适配。

  • HttpURLConnection 适配时,为 40Kb 左右
  • OkHttp 适配时,为 3.2 Mb 左右(项目里有 OkHttp 依赖时)

v3.0 后,同时做为 solon-test 和 nami-channel-http 的内部工具。

2、基本操作

  • HEAD 请求
int code = HttpUtils.http("http://localhost:8080/hello").head();
  • GET 请求
String body = HttpUtils.http("http://localhost:8080/hello").get();
//for Bean
Book book = HttpUtils.http("http://localhost:8080/book?bookId=1")
                     .getAs(Book.class);
  • POST 请求
//x-www-form-urlencoded
String body = HttpUtils.http("http://localhost:8080/hello")
                       .data("name","world")
                       .post();

//form-data
String body = HttpUtils.http("http://localhost:8080/hello")
                       .data("name","world")
                       .post(true); // useMultipart
                       
//form-data :: upload-file
String body = HttpUtils.http("http://localhost:8080/hello")
                       .data("name", new File("/data/demo.jpg"))
                       .post(true); // useMultipart
                       
//body-json
String body = HttpUtils.http("http://localhost:8080/hello")
                       .bodyOfJson("{\"name\":\"world\"}")
                       .post();
//for Bean
Result body = HttpUtils.http("http://localhost:8080/book")
                       .bodyOfBean(book)
                       .postAs(Result.class);
                       
                       
//for Bean generic type
Result<User> body = HttpUtils.http("http://localhost:8080/book")
                       .bodyOfBean(book)
                       .postAs(new Result<User>(){}.getClass()); //通过临时类构建泛型(或别的方式)
  • PUT 请求
String body = HttpUtils.http("http://localhost:8080/hello")
                       .data("name","world")
                       .put();
//for Bean
Result body = HttpUtils.http("http://localhost:8080/book")
                       .bodyOfBean(book)
                       .putAs(Result.class);
  • PATCH 请求
String body = HttpUtils.http("http://localhost:8080/hello")
                       .data("name","world")
                       .patch();
//for Bean
Result body = HttpUtils.http("http://localhost:8080/book")
                       .bodyOfBean(book)
                       .patchAs(Result.class);
  • DELETE 请求
String body = HttpUtils.http("http://localhost:8080/hello")
                       .data("name","world")
                       .delete();
//for Bean
Result body = HttpUtils.http("http://localhost:8080/book")
                       .bodyOfBean(book)
                       .deleteAs(Result.class);

3、高级操作

获取响应(用完要关闭)

try(HttpResponse resp = HttpUtils.http("http://localhost:8080/hello").data("name","world").exec("POST")) {
    int code = resp.code();
    String head = resp.header("Demo-Header");
    String body = resp.bodyAsString();
}

配置序列化器。默认为 json,改为 fury;或者自己定义。

FuryBytesSerializer serializer = new FuryBytesSerializer();

Result body = HttpUtils.http("http://localhost:8080/book")
                       .serializer(serializer)
                       .bodyOfBean(book)
                       .postAs(Result.class);

定制扩展(统一添加头信息等...)

//注解模式
@Component
public class HttpExtensionImpl implements HttpExtension {
    @Override
    public void onInit(HttpUtils httpUtils, String url) {
        httpUtils.header("TOKEN","xxxx");
    }
}

//手动模式
HttpConfiguration.addExtension((httpUtils, url)->{
    httpUtils.header("TOKEN","xxxx");
});

4、其它操作

基于服务名的调用示例:(内部是基于注册与发布服务)

public class App {
    public static void maing(String[] args) {
        Solon.start(App.class, args);

        //通过服务名进行http请求
        HttpUtils.http("HelloService","/hello").get();
        HttpUtils.http("HelloService","/hello").data("name", "world").put();
        HttpUtils.http("HelloService","/hello").bodyOfJson("{\"name\":\"world\"}").post();
    }
}

顺带放了一个预热工具,让自己可以请求自己。从而达到简单预热效果:

public class App {
    public static void maing(String[] args) {
        Solon.start(App.class, args);

        //用http请求自己进行预热
        PreheatUtils.preheat("/healthz");

        //用bean预热
        HelloService service = Solon.context().getBean(HelloService.class);
        service.hello();
    }
}

5、接口说明

public interface HttpUtils {
    static final Logger log = LoggerFactory.getLogger(HttpUtils.class);

    static HttpUtils http(String service, String path) {
        String url = LoadBalanceUtils.getServer(null, service) + path;
        return http(url);
    }

    static HttpUtils http(String group, String service, String path) {
        String url = LoadBalanceUtils.getServer(group, service) + path;
        return http(url);
    }

    static HttpUtils http(String url) {
        if (ClassUtil.hasClass(() -> OkHttpClient.class)) {
            return new OkHttpUtilsImpl(url);
        } else {
            return new JdkHttpUtilsImpl(url);
        }
    }

    /**
     * 配置序列化器
     */
    HttpUtils serializer(Serializer serializer);

    /**
     * 获取序列化器
     */
    Serializer serializer();

    /**
     * 启用打印(专为 tester 服务)
     */
    HttpUtils enablePrintln(boolean enable);

    /**
     * 超时配置
     */
    HttpUtils timeout(int timeoutSeconds);

    /**
     * 超时配置
     */
    HttpUtils timeout(int connectTimeoutSeconds, int writeTimeoutSeconds, int readTimeoutSeconds);

    /**
     * 是否多部分配置
     */
    HttpUtils multipart(boolean multipart);

    /**
     * 用户代理配置
     */
    HttpUtils userAgent(String ua);

    /**
     * 编码配置
     */
    HttpUtils charset(String charset);

    /**
     * 头配置
     */
    HttpUtils headers(Map headers);

    /**
     * 头配置
     */
    HttpUtils headers(Iterable<KeyValues<String>> headers);

    /**
     * 头配置(替换)
     */
    HttpUtils header(String name, String value);

    /**
     * 头配置(添加)
     */
    HttpUtils headerAdd(String name, String value);

    /**
     * 小饼配置
     */
    HttpUtils cookies(Map cookies);

    /**
     * 小饼配置
     */
    HttpUtils cookies(Iterable<KeyValues<String>> cookies);

    /**
     * 小饼配置(替换)
     */
    HttpUtils cookie(String name, String value);

    /**
     * 小饼配置(添加)
     */
    HttpUtils cookieAdd(String name, String value);

    /**
     * 参数配置
     */
    HttpUtils data(Map data);

    /**
     * 参数配置
     */
    HttpUtils data(Iterable<KeyValues<String>> data);

    /**
     * 参数配置(替换)
     */
    HttpUtils data(String name, String value);

    /**
     * 参数配置
     */
    HttpUtils data(String name, String filename, InputStream inputStream, String contentType);

    /**
     * 参数配置
     */
    HttpUtils data(String name, String filename, File file);

    /**
     * 参数配置
     */
    default HttpUtils data(String name, File file) {
        return data(name, file.getName(), file);
    }

    /**
     * 主体配置
     */
    default HttpUtils bodyOfTxt(String txt) {
        return body(txt, "text/plain");
    }

    /**
     * 主体配置
     */
    default HttpUtils bodyOfJson(String txt) {
        return body(txt, "application/json");
    }

    /**
     * 主体配置(由序列化器决定内容类型)
     */
    HttpUtils bodyOfBean(Object obj) throws IOException;

    /**
     * 主体配置
     */
    HttpUtils body(String txt, String contentType);

    /**
     * 主体配置
     */
    HttpUtils body(byte[] bytes, String contentType);

    /**
     * 主体配置
     */
    default HttpUtils body(byte[] bytes) {
        return body(bytes, null);
    }

    /**
     * 主体配置
     */
    HttpUtils body(InputStream raw, String contentType);

    /**
     * 主体配置
     */
    default HttpUtils body(InputStream raw) {
        return body(raw, null);
    }


    /**
     * get 请求并返回 body
     */
    String get() throws IOException;

    /**
     * get 请求并返回 body
     */
    <T> T getAs(Type type) throws IOException;

    /**
     * post 请求并返回 body
     */
    String post() throws IOException;

    /**
     * post 请求并返回 body
     */
    <T> T postAs(Type type) throws IOException;

    /**
     * post 请求并返回 body
     */
    default String post(boolean useMultipart) throws IOException {
        if (useMultipart) {
            multipart(true);
        }

        return post();
    }

    /**
     * post 请求并返回 body
     */
    default <T> T postAs(Type type, boolean useMultipart) throws IOException {
        if (useMultipart) {
            multipart(true);
        }

        return postAs(type);
    }

    /**
     * put 请求并返回 body
     */
    String put() throws IOException;

    /**
     * put 请求并返回 body
     */
    <T> T putAs(Type type) throws IOException;

    /**
     * patch 请求并返回 body
     */
    String patch() throws IOException;

    /**
     * patch 请求并返回 body
     */
    <T> T patchAs(Type type) throws IOException;

    /**
     * delete 请求并返回 body
     */
    String delete() throws IOException;

    /**
     * delete 请求并返回 body
     */
    <T> T deleteAs(Type type) throws IOException;


    /**
     * options 请求并返回 body
     */
    String options() throws IOException;

    /**
     * head 请求并返回 code
     */
    int head() throws IOException;

    //////

    /**
     * 执行请求并返回响应主体
     */
    String execAsBody(String method) throws IOException;

    /**
     * 执行请求并返回响应主体
     */
    <T> T execAsBody(String method, Type type) throws IOException;

    /**
     * 执行请求并返回代码
     */
    int execAsCode(String method) throws IOException;

    /**
     * 执行请求并返回响应
     */
    HttpResponse exec(String method) throws IOException;

    /**
     * 异步执行请求
     */
    CompletableFuture<HttpResponse> execAsync(String method);
}