知乎专栏 |
http://square.github.io/okhttp/
再 app/build.gradle 文件中增加依赖包
implementation "com.squareup.okhttp3:okhttp:4.10.0"
app/build.gradle
neo@MacBook-Pro ~/AndroidStudioProjects/okhttp % cat app/build.gradle apply plugin: 'com.android.application' android { compileSdkVersion 28 defaultConfig { applicationId "cn.netkiller.okhttp" minSdkVersion 28 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support:design:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation 'com.squareup.okhttp3:okhttp:3.11.0' }
在 app/src/main/AndroidManifest.xml 文件中增加
<uses-permission android:name="android.permission.INTERNET" />
否则 okhttp 无法访问网络,添加后的效果如下。
neo@MacBook-Pro ~/AndroidStudioProjects/okhttp % cat app/src/main/AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.netkiller.okhttp"> <uses-permission android:name="android.permission.INTERNET" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
如果你尝试使用 http 链接 OkHttp3 就抛出异常: CLEARTEXT communication to " + host + " not permitted by network security policy
开发过程中由于 https ssl 需要购买证书,费用较高,通常测试环境我们仍然使用 http 下面方法是开启 http 模式,
创建文件 res/xml/network_security_config.xml 内容如下
neo@MacBook-Pro ~/AndroidStudioProjects/okhttp % cat app/src/main/res/xml/network_security_config.xml <?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="true">localhost</domain> </domain-config> </network-security-config>
再 app/src/main/AndroidManifest.xml 文件中增加 android:networkSecurityConfig="@xml/network_security_config"
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.netkiller.okhttp"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:label="@string/app_name" android:networkSecurityConfig="@xml/network_security_config"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-permission android:name="android.permission.INTERNET" /> </manifest>
ConnectionPool connectionPool = new ConnectionPool(10, 5, TimeUnit.MINUTES); OkHttpClient client = new OkHttpClient.Builder() .connectionPool(connectionPool) .retryOnConnectionFailure(true) .connectTimeout(5, TimeUnit.MINUTES) .readTimeout(5, TimeUnit.MINUTES) .writeTimeout(Duration.ofSeconds(90)) .callTimeout(Duration.ofSeconds(90)) .build(); client.dispatcher().setMaxRequestsPerHost(200); client.dispatcher().setMaxRequests(200);
OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("http://www.netkiller.cn") .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) { throw new IOException("服务器端错误: " + response); } Headers responseHeaders = response.headers(); for (int i = 0; i < responseHeaders.size(); i++) { System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i)); } System.out.println(response.body().string());
HttpUrl.Builder urlBuilder = HttpUrl.parse("https://www.netkiller.cn").newBuilder(); urlBuilder.addPathSegments("search/cache_vector_chatgpt"); urlBuilder.addQueryParameter("question", "Helloworld!!!"); String url = urlBuilder.build().toString(); Log.d("API", url); OkHttpClient client = new OkHttpClient(); try { Request request = new Request.Builder().url(url).build(); Response response = client.newCall(request).execute(); if (response.isSuccessful()) { Log.d("API", response.body().string()); } } catch (IOException e) { throw new RuntimeException(e); }
URL 输出
https://www.netkiller.cn/search/cache_vector_chatgpt?question=Helloworld%21%21%21
OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(url).build(); Call call = client.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { if (response.isSuccessful()) { Log.i("TAG", "Async: " + response.body().string()); } } });
from 数据如下
key=value&other=data
String url = "https://api.netkiller.cn/oauth/token"; OkHttpClient client = new OkHttpClient(); RequestBody formBody = new FormBody.Builder() .add("grant_type", "password") .add("username", "netkiller") .add("password", "123456") .build(); Request request = new Request.Builder() .url(url) .post(formBody) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) { throw new IOException("服务器端错误: " + response); }
POST RAW Json 数据,数据的形态这样的
{"key":"value"}
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); OkHttpClient client = new OkHttpClient(); String post(String url, String json) throws IOException { RequestBody body = RequestBody.create(JSON, json); Request request = new Request.Builder() .url(url) .post(body) .build(); Response response = client.newCall(request).execute(); return response.body().string(); }
OkHttpClient client = new OkHttpClient(); final MediaType MEDIA_TYPE_TEXT = MediaType.parse("text/plain"); final String postBody = "Hello World"; RequestBody requestBody = new RequestBody() { @Override public MediaType contentType() { return MEDIA_TYPE_TEXT; } @Override public void writeTo(BufferedSink sink) throws IOException { sink.writeUtf8(postBody); } @Override public long contentLength() throws IOException { return postBody.length(); } }; Request request = new Request.Builder() .url("https://www.google.com") .post(requestBody) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) { throw new IOException("服务器端错误: " + response); } System.out.println(response.body().string());
import java.util.concurrent.TimeUnit; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; public class Test { public static void main(String[] args) throws Exception { String url = "http://****"; String json = "{\"param\":\"value2\",\"key\":\"value\"}"; OkHttpClient client = new OkHttpClient().newBuilder() // .readTimeout(60, TimeUnit.SECONDS) // 设置读取超时时间 .writeTimeout(60, TimeUnit.SECONDS) // 设置写的超时时间 .connectTimeout(60, TimeUnit.SECONDS) // 设置连接超时时间 .build(); MediaType JSON = MediaType.parse("application/json; charset=utf-8"); RequestBody body = RequestBody.create(json, JSON); Request request = new Request.Builder().url(url).put(body).build(); try (Response response = client.newCall(request).execute()) { System.out.println(response.body().string()); } } }
添加Http头
Request request = new Request.Builder() .url(url) .addHeader("CLIENT", "AD") .addHeader("USERID", "343") .build();
覆盖 HTTP 头
Request request = new Request.Builder() .header("Authorization", "replace this text with your token") .url(url) .build();
public class Headers { public static void main(String[] args) throws IOException { OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("http://www.netkiller.cn") .header("User-Agent", "Apple Mac") .addHeader("Accept", "text/html") .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) { throw new IOException("服务器端错误: " + response); } System.out.println(response.header("Server")); System.out.println(response.headers("Set-Cookie")); } }
OkHttpClient mHttpClient = new OkHttpClient.Builder().cookieJar(new CookieJar() { private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>(); @Override public void saveFromResponse(HttpUrl url, List<Cookie> cookies) { cookieStore.put(url.host(), cookies); } @Override public List<Cookie> loadForRequest(HttpUrl url) { List<Cookie> cookies = cookieStore.get(url.host()); return cookies != null ? cookies : new ArrayList<Cookie>(); } }).build();
Request request = new Request.Builder() .cacheControl(new CacheControl.Builder().noCache().build()) .url(url) .build();
// 等同于 nocache Request request = new Request.Builder() .cacheControl(new CacheControl.Builder() .maxAge(0, TimeUnit.SECONDS) .build()) .url("https://www.netkiller.cn") .build(); // 设置缓存 365 天 Request request = new Request.Builder() .cacheControl(new CacheControl.Builder() .maxStale(365, TimeUnit.DAYS) .build()) .url("https://www.netkiller.cn") .build();
Request request = new Request.Builder() .cacheControl(new CacheControl.Builder() .onlyIfCached() .build()) .url("https://www.netkiller.cn/helloworld.txt") .build(); Response forceCacheResponse = client.newCall(request).execute(); if (forceCacheResponse.code() != 504) { // The resource was cached! Show it. } else { // The resource was not cached. }
OkHttpClient 方案
OkHttpClient client = new OkHttpClient.Builder().authenticator( new Authenticator(){ public Request authenticate(Route route, Response response) { String credential = Credentials.basic("api","secret"); return response.request().newBuilder().header("Authorization", credential).build(); } } ).build();
Request 方案
public void post(String function, File file, Callback responseCallback) { HttpUrl.Builder urlBuilder = HttpUrl.parse(address).newBuilder(); urlBuilder.addPathSegments(function); // urlBuilder.addQueryParameter("sentence", question); String url = urlBuilder.build().toString(); Log.i(TAG, "Post URL: " + url); OkHttpClient client = this.client(); String credential = Credentials.basic(username, password); RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) .addFormDataPart("file", file.getName(), RequestBody.create(file, MediaType.parse("multipart/form-data"))) .build(); Request request = new Request.Builder().url(url) // .addHeader("token", token) .addHeader("Authorization", credential) .post(requestBody).build(); client.newCall(request).enqueue(responseCallback); }
使用字符串拼接 URL地址特别容易出错
String url = "https://www.netkiller.cn/article?username="+ username + "&category="+ category;
较好的处理方式是使用 HttpUrl.Builder
HttpUrl.Builder builder = HttpUrl.parse("https://www.netkiller.cn/article").newBuilder(); builder.addQueryParameter("username", "netkiller"); builder.addQueryParameter("category", "android"); String url = builder.build().toString(); Log.d("okhttp", url);
输出结果
https://www.netkiller.cn/article?username=netkiller&category=android
package cn.netkiller.okhttp; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.TextView; import java.io.IOException; import okhttp3.Call; import okhttp3.Callback; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class HttpActivity extends AppCompatActivity { TextView textView; private Handler mHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_http); textView = (TextView) findViewById(R.id.textView); mHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { textView.setText((String) msg.obj); } }; OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url("https://api.netkiller.cn/member/json").build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.d("okhttp", "Connect timeout. " + e.getMessage()); } @Override public void onResponse(Call call, Response response) throws IOException { String text = response.body().string(); Log.d("okhttp", "HTTP Code " + response.code() + " TEXT " + text); Message msg = new Message(); msg.what = 0; msg.obj = text; mHandler.sendMessage(msg); } }); } }
Oauth 返回数据,通过 Gson 的 fromJson 存储到下面类中。
package cn.netkiller.okhttp.pojo; public class Oauth { private String access_token; private String token_type; private String refresh_token; private String expires_in; private String scope; private String jti; public String getAccess_token() { return access_token; } public void setAccess_token(String access_token) { this.access_token = access_token; } public String getToken_type() { return token_type; } public void setToken_type(String token_type) { this.token_type = token_type; } public String getRefresh_token() { return refresh_token; } public void setRefresh_token(String refresh_token) { this.refresh_token = refresh_token; } public String getExpires_in() { return expires_in; } public void setExpires_in(String expires_in) { this.expires_in = expires_in; } public String getScope() { return scope; } public void setScope(String scope) { this.scope = scope; } public String getJti() { return jti; } public void setJti(String jti) { this.jti = jti; } @Override public String toString() { return "Oauth{" + "access_token='" + access_token + '\'' + ", token_type='" + token_type + '\'' + ", refresh_token='" + refresh_token + '\'' + ", expires_in='" + expires_in + '\'' + ", scope='" + scope + '\'' + ", jti='" + jti + '\'' + '}'; } }
Activity 文件
package cn.netkiller.okhttp; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.widget.TextView; import com.google.gson.Gson; import java.io.IOException; import cn.netkiller.okhttp.pojo.Oauth; import okhttp3.Authenticator; import okhttp3.Call; import okhttp3.Callback; import okhttp3.Credentials; import okhttp3.FormBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; import okhttp3.Route; public class Oauth2jwtActivity extends AppCompatActivity { private TextView token; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_oauth2jwt); token = (TextView) findViewById(R.id.token); try { get(); } catch (IOException e) { e.printStackTrace(); } } public static Oauth accessToken() throws IOException { OkHttpClient client = new OkHttpClient.Builder().authenticator( new Authenticator() { public Request authenticate(Route route, Response response) { String credential = Credentials.basic("api", "secret"); return response.request().newBuilder().header("Authorization", credential).build(); } } ).build(); String url = "https://api.netkiller.cn/oauth/token"; RequestBody formBody = new FormBody.Builder() .add("grant_type", "password") .add("username", "blockchain") .add("password", "123456") .build(); Request request = new Request.Builder() .url(url) .post(formBody) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) { throw new IOException("服务器端错误: " + response); } Gson gson = new Gson(); Oauth oauth = gson.fromJson(response.body().string(), Oauth.class); Log.i("oauth", oauth.toString()); return oauth; } public void get() throws IOException { OkHttpClient client = new OkHttpClient.Builder().authenticator( new Authenticator() { public Request authenticate(Route route, Response response) throws IOException { return response.request().newBuilder().header("Authorization", "Bearer " + accessToken().getAccess_token()).build(); } } ).build(); String url = "https://api.netkiller.cn/misc/compatibility"; Request request = new Request.Builder() .url(url) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { call.cancel(); } @Override public void onResponse(Call call, Response response) throws IOException { final String myResponse = response.body().string(); runOnUiThread(new Runnable() { @Override public void run() { Log.i("oauth", myResponse); token.setText(myResponse); } }); } }); } public void post() throws IOException { OkHttpClient client = new OkHttpClient.Builder().authenticator( new Authenticator() { public Request authenticate(Route route, Response response) throws IOException { return response.request().newBuilder().header("Authorization", "Bearer " + accessToken().getAccess_token()).build(); } } ).build(); String url = "https://api.netkiller.cn/history/create"; String json = "{\n" + " \"assetsId\": \"5bced71c432c001c6ea31924\",\n" + " \"title\": \"添加信息\",\n" + " \"message\": \"信息内容\",\n" + " \"status\": \"录入\"\n" + "}"; final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); RequestBody body = RequestBody.create(JSON, json); Request request = new Request.Builder() .url(url) .post(body) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { call.cancel(); } @Override public void onResponse(Call call, Response response) throws IOException { final String myResponse = response.body().string(); runOnUiThread(new Runnable() { @Override public void run() { // Gson gson = new Gson(); // Oauth oauth = gson.fromJson(myResponse, Oauth.class); // Log.i("oauth", oauth.toString()); token.setText(myResponse); } }); } }); } }
上面的例子演示了,怎样获取 access token 以及 HTTP 基本操作 GET 和 POST,再Restful接口中还可能会用到 PUT, DELETE 等等,原来相同,这里就不在演示。
首先确认你的服务器是支持 HTTP2,HTTP2配置方法可以参考 《Netkiller Web 手札》
下面是我的例子仅供参考,Nginx 开启 http2 代理后面的 Spring Cloud 接口。
server { listen 80; listen 443 ssl http2; server_name api.netkiller.cn; ssl_certificate ssl/netkiller.cn.crt; ssl_certificate_key ssl/netkiller.cn.key; ssl_session_cache shared:SSL:20m; ssl_session_timeout 60m; charset utf-8; access_log /var/log/nginx/api.netkiller.cn.access.log; error_page 497 https://$host$uri?$args; if ($scheme = http) { return 301 https://$server_name$request_uri; } location / { proxy_pass http://127.0.0.1:8000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} }
安卓程序如下
String url = "https://api.netkiller.cn/member/json"; OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(url).build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { Log.d("okhttp", "Connect timeout. " + e.getMessage()); } @Override public void onResponse(Call call, Response response) throws IOException { String text = response.body().string(); Log.d("okhttp", "HTTP Code " + response.code() + " TEXT " + text); Log.d("okhttp", "Protocol: " + response.protocol()); } });
运行结果
D/okhttp: HTTP Code 200 TEXT {"status":false,"reason":"","code":0,"data":{"id":null,"username":"12322228888","mobile":"12322228888","password":"123456","wechat":"微信ID","role":"Organization","captcha":null,"createDate":"2018-10-25 09:25:23","updateDate":null}} Protocol: h2
输出 h2 表示当前接口与服务器连接是通过 http2 完成。
buttonSend.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { HttpUrl.Builder urlBuilder = HttpUrl.parse(apiUrl).newBuilder(); urlBuilder.addPathSegments("search/cache_vector_chatgpt"); urlBuilder.addQueryParameter("question", editTextMessage.getText().toString()); String url = urlBuilder.build().toString(); Log.d("API", url); OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(url).build(); Call call = client.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { if (response.isSuccessful()) { answer = response.body().string(); updateResult(answer); Log.i("TAG", "Async: " + answer); } } }); } });
private void updateResult(final String response) { //在子线程中更新UI getActivity().runOnUiThread(new Runnable() { @Override public void run() { // 在这里进行UI操作,将结果显示到界面上 text_dashboard.setText(response); } }); }
Lambda 表达式
private void showResponse(final String response) { //在子线程中更新UI runOnUiThread(() -> { // 在这里进行UI操作,将结果显示到界面上 responseText.setText(response); }); }
在 Fragment 中需这样使用 getActivity().runOnUiThread()
buttonSend.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { HttpUrl.Builder urlBuilder = HttpUrl.parse(apiUrl).newBuilder(); urlBuilder.addPathSegments("search/cache_vector_chatgpt"); urlBuilder.addQueryParameter("question", editTextMessage.getText().toString()); String url = urlBuilder.build().toString(); Log.d("API", url); OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(url).build(); Call call = client.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { } @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { if (response.isSuccessful()) { answer = response.body().string(); getActivity().runOnUiThread(() -> { text_dashboard.setText(answer); }); Log.i("TAG", "Async: " + answer); } } }); } });
public void postStream(String function, LinkedHashMap<String, String> params, String json) throws InterruptedException { HttpUrl.Builder urlBuilder = HttpUrl.parse(address).newBuilder(); urlBuilder.addPathSegments(function); if (params != null) { for (Map.Entry<String, String> entry : params.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); urlBuilder.addQueryParameter(key, value); } } String url = urlBuilder.build().toString(); Log.d(TAG, "Post URL: " + url + " Json: " + json); MediaType mediaType = MediaType.parse("application/json; charset=utf-8"); RequestBody body = RequestBody.create(json, mediaType); Request request = new Request.Builder() .url(url) // .addHeader("Authorization", "Bearer " + token) .addHeader("Accept", "text/event-stream") // .addHeader("accept-encoding", "gzip, deflate") .addHeader("token", this.token) .post(body).build(); OkHttpClient client = this.client(); RealEventSource realEventSource = new RealEventSource(request, new EventSourceListener() { @Override public void onOpen(EventSource eventSource, Response response) { Log.d(TAG, "onOpen"); } @Override public void onEvent(EventSource eventSource, String id, String type, String data) { Log.d(TAG, "Stream Id: " + id + " Type: " + type + " Data: " + data); // 请求到的数据 } @Override public void onClosed(EventSource eventSource) { Log.d(TAG, "onClosed"); } @Override public void onFailure(EventSource eventSource, Throwable throwable, Response response) { Log.d(TAG, "onFailure");//这边可以监听并重新打开 Log.d(TAG, response.toString()); Log.d(TAG, throwable.toString()); } }); realEventSource.connect(client); }
public void getStream(String function, LinkedHashMap<String, String> params, EventSourceListener listener) throws InterruptedException { HttpUrl.Builder urlBuilder = HttpUrl.parse(address).newBuilder(); urlBuilder.addPathSegments(function); if (params != null) { for (Map.Entry<String, String> entry : params.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); urlBuilder.addQueryParameter(key, value); } } String url = urlBuilder.build().toString(); // Log.d(TAG, "Post URL: " + url + " params: " + params.toString()); Request request = new Request.Builder() .url(url) // .addHeader("Authorization", "Bearer " + token) .addHeader("Accept", "text/event-stream; charset=utf-8") // .addHeader("accept-encoding", "gzip, deflate") .addHeader("token", this.token) .get().build(); OkHttpClient client = this.client(); EventSource.Factory createFactory = EventSources.createFactory(client); // EventSourceListener eventSourceListener = new EventSourceListener() { // @Override // public void onEvent(EventSource eventSource, String id, String type, String data) { // // Log.d(TAG, "Stream Id: " + id + " Type: " + type + " Data: " + data); // 请求到的数据 // } // // public void onFailure(EventSource eventSource, Throwable throwable, Response response) { // super.onFailure(eventSource, throwable, response); // Log.d(TAG, response.toString()); // Log.d(TAG, throwable.toString()); // } // }; createFactory.newEventSource(request, listener); }
package cn.netkiller.service; import lombok.extern.slf4j.Slf4j; import okhttp3.*; import org.reactivestreams.Publisher; import org.springframework.stereotype.Component; import org.springframework.web.reactive.socket.WebSocketHandler; import org.springframework.web.reactive.socket.WebSocketMessage; import org.springframework.web.reactive.socket.WebSocketSession; import org.springframework.web.reactive.socket.client.StandardWebSocketClient; import org.springframework.web.reactive.socket.client.WebSocketClient; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.concurrent.TimeUnit; @Component @Slf4j public class WebSocketService { private final OkHttpClient webSocketClient; private final Request request; String url = "wss://socketsbay.com/wss/v2/1/demo/"; private WebSocket webSocket; public WebSocketService() { webSocketClient = new OkHttpClient.Builder().pingInterval(30, TimeUnit.SECONDS).build(); log.info("WebSocket url: {}", url); // 构造请求对象 request = new Request.Builder().url(url).build(); connect(); } public void send(String text) { if (webSocket == null) { connect(); } webSocket.send(text); log.info("Send: " + text); } public void connect() { // 调用websocket服务端 webSocket = webSocketClient.newWebSocket(request, new MyWebSocketListener()); log.info(webSocket.toString()); } class MyWebSocketListener extends WebSocketListener { /** * websocket连接建立后来到这个方法 * * @param webSocket * @param response */ @Override public void onOpen(WebSocket webSocket, Response response) { super.onOpen(webSocket, response); try { log.info("onOpen: " + response.body().string()); } catch (IOException e) { } } @Override public void onMessage(WebSocket webSocket, String text) { super.onMessage(webSocket, text); log.info("Receive: " + text); } // @Override // public void onMessage(WebSocket webSocket, ByteString bytes) { // super.onMessage(webSocket, bytes); // } @Override public void onClosing(WebSocket webSocket, int code, String reason) { super.onClosing(webSocket, code, reason); log.info("onClosing code: " + code + " reason: " + reason); } @Override public void onClosed(WebSocket webSocket, int code, String reason) { super.onClosed(webSocket, code, reason); log.info("onClosed code: " + code + " reason: " + reason); } @Override public void onFailure(WebSocket webSocket, Throwable t, Response response) { super.onFailure(webSocket, t, response); if (response == null) { log.error("onFailure, response is null."); return; } try { log.error("onFailure, code: {}, errmsg: {}", response.code(), response.body().string()); } catch (IOException e) { log.warn("onFailure failed, error: {}", e.getMessage()); } } } }
package cn.aigcsst.student.cloud; import android.util.Log; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Proxy; import java.util.List; import okhttp3.Call; import okhttp3.EventListener; import okhttp3.Handshake; import okhttp3.Protocol; import okhttp3.Request; import okhttp3.Response; public class LoggingEventListener extends EventListener { private static final String TAG = LoggingEventListener.class.getSimpleName(); private Long mCallStartTime = null; private Long mCallEndTime = null; private Long mDnsStartTime = null; private Long mDnsEndTime = null; private Long mConnectStartTime = null; private Long mSecureConnectStartTime = null; private Long mSecureConnectEndTime = null; private Long mConnectEndTime = null; private Long mRequestHeadersStartTime = null; private Long mRequestHeadersEndTime = null; private Long mResponseHeadersStartTime = null; private Long mResponseHeadersEndTime = null; private Long mResponseBodyStartTime = null; private Long mResponseBodyEndTime = null; @Override public void callStart(Call call) { mCallStartTime = System.currentTimeMillis(); Log.i(TAG, "Event callStart at " + mCallStartTime); } @Override public void dnsStart(Call call, String domainName) { mDnsStartTime = System.currentTimeMillis(); Log.i(TAG, "Event dnsStart at " + mDnsStartTime); } @Override public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList) { mDnsEndTime = System.currentTimeMillis(); Log.i(TAG, "Event dnsEnd at " + mDnsEndTime + " dnsDuration is " + (mDnsEndTime - mDnsStartTime) + " ms"); } @Override public void connectStart(Call call, InetSocketAddress inetSocketAddress, Proxy proxy) { mConnectStartTime = System.currentTimeMillis(); Log.i(TAG, "Event connectStart at " + mConnectStartTime); } @Override public void secureConnectStart(Call call) { mSecureConnectStartTime = System.currentTimeMillis(); Log.i(TAG, "Event secureConnectStart at " + mSecureConnectStartTime); } @Override public void secureConnectEnd(Call call, Handshake handshake) { mSecureConnectEndTime = System.currentTimeMillis(); Log.i(TAG, "Event secureConnectEnd at " + mSecureConnectEndTime + " secureConnectDuration is " + (mSecureConnectEndTime - mSecureConnectStartTime) + " ms"); } @Override public void connectEnd(Call call, InetSocketAddress inetSocketAddress, Proxy proxy, Protocol protocol) { mConnectEndTime = System.currentTimeMillis(); Log.i(TAG, "Event connectEnd at " + mConnectEndTime + " ConnectDuration is " + (mConnectEndTime - mConnectStartTime) + " ms"); } @Override public void requestHeadersStart(Call call) { mRequestHeadersStartTime = System.currentTimeMillis(); Log.i(TAG, "Event requestHeadersStart at " + mRequestHeadersStartTime); } @Override public void requestHeadersEnd(Call call, Request request) { mRequestHeadersEndTime = System.currentTimeMillis(); Log.i(TAG, "Event requestHeadersEnd at " + mRequestHeadersEndTime + " requestHeadersDuration is " + (mRequestHeadersEndTime - mRequestHeadersStartTime) + " ms"); } @Override public void responseHeadersStart(Call call) { mResponseHeadersStartTime = System.currentTimeMillis(); Log.i(TAG, "Event responseHeadersStart at " + mResponseHeadersStartTime); } @Override public void responseHeadersEnd(Call call, Response response) { mResponseHeadersEndTime = System.currentTimeMillis(); Log.i(TAG, "Event responseHeadersEnd at " + mResponseHeadersEndTime + " responseHeadersDuration is " + (mResponseHeadersEndTime - mResponseHeadersStartTime) + " ms"); } @Override public void responseBodyStart(Call call) { mResponseBodyStartTime = System.currentTimeMillis(); Log.i(TAG, "Event responseBodyStart at " + mResponseBodyStartTime); } public void responseBodyEnd(Call call, Long byteCount) { mResponseBodyEndTime = System.currentTimeMillis(); Log.i(TAG, "Event responseBodyEnd at " + mResponseBodyEndTime + " responseHeadersDuration is " + (mResponseBodyEndTime - mResponseBodyStartTime) + " ms"); } @Override public void callEnd(Call call) { mCallEndTime = System.currentTimeMillis(); Log.i(TAG, "Event callEnd at " + mCallEndTime + " responseHeadersDuration is " + (mCallEndTime - mCallStartTime) + " ms"); } @Override public void callFailed(Call call, IOException ioe) { Log.i(TAG, "Request Failed: " + ioe.getMessage()); } }
private OkHttpClient client() { OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder() .eventListener(new LoggingEventListener()) .retryOnConnectionFailure(true) .connectTimeout(60, TimeUnit.SECONDS) .writeTimeout(60, TimeUnit.SECONDS) .readTimeout(60, TimeUnit.SECONDS) .callTimeout(Duration.ofSeconds(60)).dns(new IPv6Dns()); // .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)); // if (authenticator != null) { // okHttpClient.authenticator(authenticator); // } return okHttpClient.build(); }