solon-net-httputils
<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);
}