HTTP GET请求示例代码:
```java
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class HttpGetExample {
public static void main(String[] args) throws IOException {
OkHttpClient client = new OkHttpClient();
String url = "https://api.example.com/data";
String result = run(url);
System.out.println(result);
}
public static String run(String url) throws IOException {
Request request = new Request.Builder().url(url).build();
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("Unexpected code " + response);
}
}
}
```
Response类示例代码:
```java
import okhttp3.Response;
public class ResponseExample {
public static void main(String[] args) {
// 这里需要一个实际的响应对象,例如从网络请求中获取的Response对象
Response response = null;
boolean isSuccessful = response.isSuccessful();
System.out.println("Is successful: " + isSuccessful);
}
}
```
```java
public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
String post(String url, Map
StringBuilder json = new StringBuilder();
for (Map.Entry
if (json.length() != 0) {
json.append('&');
}
json.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
json.append('=');
json.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
}
RequestBody body = RequestBody.create(JSON, json.toString());
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("Unexpected code " + response);
}
}
```
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("Unexpected code " + response);
}
}
总结:通过上面的例子我们可以发现,OkHttp在很多时候使用都是很方便的,而且很多代码也有重复。因此,特地整理了下面的工具类。注意:OkHttp官方文档并不建议我们创建多个OkHttpClient,因此全局使用一个。如果有需要,可以使用clone方法,再进行自定义。这点在后面的高级教程里会提到。enqueue为OkHttp提供的异步方法,入门教程中并没有提到,后面的高级教程里会有解释。
```java
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.message.BasicNameValuePair;
import cn.wiz.sdk.constant.WizConstant;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
public class OkHttpUtil {
private static final OkHttpClient mOkHttpClient = new OkHttpClient();
static{
mOkHttpClient.setConnectTimeout(30, TimeUnit.SECONDS);
}
/**
* 该不会开启异步线程。
* @param request
* @return
*/
public String sendRequest(Request request) throws IOException {
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("Unexpected code " + response);
}
}
```
这是一个使用OkHttp库发送网络请求的Java代码。重构后的内容如下:
```java
/**
* @throws IOException
*/
public static Response execute(Request request) throws IOException {
return mOkHttpClient.newCall(request).execute();
}
/**
* 开启异步线程访问网络
* @param request
* @param responseCallback
*/
public static void enqueue(Request request, final Call.Callback responseCallback) {
mOkHttpClient.newCall(request).enqueue(responseCallback);
}
/**
* 开启异步线程访问网络, 且不在意返回结果(实现空callback)
* @param request
*/
public static void enqueue(Request request) {
mOkHttpClient.newCall(request).enqueue(new Call.Callback() {
@Override
public void onResponse(Call call, Response response) throws IOException {
}
@Override
public void onFailure(Call call, IOException e) {
}
});
}
/**
* 从服务器获取字符串数据
* @param url String类型,表示服务器的URL地址
* @return 返回服务器响应的数据字符串,如果请求不成功,抛出IOException异常
* @throws IOException
*/
public static String getStringFromServer(String url) throws IOException {
Request request = new Request.Builder().url(url).build();
Response response = execute(request);
if (response.isSuccessful()) {
String responseUrl = response.body().string();
return responseUrl;
} else {
throw new IOException("Unexpected code " + response);
}
}
```
重构后的内容如下:
```java
private static final String CHARSET_NAME = "UTF-8";
/**
* 这里使用了HttpClinet的API。只是为了方便
* @param params
* @return
*/
public static String formatParams(List
return URLEncodedUtils.format(params, CHARSET_NAME);
}
/**
* 为HttpGet 的 url 方便的添加多个name value 参数。
* @param url
* @param params
* @return
*/
public static String attachHttpGetParams(String url, List
return url + "?" + formatParams(params);
}
/**
* 为HttpGet 的 url 方便的添加1个name value 参数。
* @param url
* @param name
* @param value
* @return
*/
public static String attachHttpGetParam(String url, String name, String value){
return url + "?" + name + "=" + value;
}
}
```
重构后的代码:
```javapublic void run() throws Exception {
Request request = new Request.Builder()
.url("http://publicobject.com/helloworld.txt")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Request request, Throwable throwable) {
throwable.printStackTrace();
}
@Override
public void onResponse(Response response) throws IOException {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + 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());
}
});
}
```
```java
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url("https://api.github.com/repos/square/okhttp/issues")
.header("User-Agent", "OkHttp Headers.java")
.addHeader("Accept", "application/json; q=0.5")
.addHeader("Accept", "application/vnd.github.v3+json")
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + 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());
}
```
以下是重构后的代码:
```java
import java.io.IOException;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class Main {
public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
String postBody = "Releases" +
"--------" +
"" +
" * _1.0_ May 6, 2013" +
" * _1.1_ June 15, 2013" +
" * _1.2_ August 11, 2013";
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody))
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
}
}
```
这段代码主要完成了以下功能:
1. 通过System.out.println()方法输出response的body内容。
2. 定义了一个MediaType对象MEDIA_TYPE_MARKDOWN,用于指定请求的内容类型为Markdown文本。
3. 创建了一个OkHttpClient对象client,用于发送网络请求。
4. 在run()方法中,构建了一个RequestBody对象requestBody,该对象包含了要发送的Markdown文本内容。同时,还定义了一个名为factor()的方法,用于计算给定数值的阶乘。
5. 使用Request.Builder构建了一个POST请求,将requestBody作为请求体发送到指定的URL(https://api.github.com/markdown/raw)。
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
Post方式提交文件
以文件作为请求体是十分简单的。
```
public static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
File file = new File("README.md");
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
```
Post方式提交表单
使用FormEncodingBuilder来构建表单数据:
```
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
FormEncodingBuilder formBody = new FormEncodingBuilder();
formBody.add("key", "value"); // key-value pairs for the form fields
// ... add more fields as needed
Request request = new Request.Builder()
.url("https://example.com/submit")
.post(formBody.build())
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
```
以下是重构后的内容:
```java
import okhttp3.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class Main {
private static final String IMGUR_CLIENT_ID = "your_imgur_client_id";
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
private final OkHttpClient client = new OkHttpClient();
public void uploadImg(String imagePath) throws Exception {
RequestBody requestBody = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addPart(
Headers.of("Content-Disposition", "form-data; name=\"file\";filename=\"" + imagePath),
RequestBody.create(new File(imagePath), MEDIA_TYPE_PNG))
.build();
Request request = new Request.Builder()
.url("https://api.imgur.com/3/image")
.header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
public static void main(String[] args) throws Exception {
Main main = new Main();
main.uploadImg("path/to/your/image.png");
}
}
```
首先,需要导入Gson和相关依赖。在项目的build.gradle文件中添加以下依赖:
```groovy
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'com.squareup.okhttp3:okhttp:4.9.1'
```
然后,创建一个名为ImgurClient的类,并在其中添加以下代码:
```java
import java.io.File;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import com.google.gson.Gson;
public class ImgurClient {
private static final String IMGUR_CLIENT_ID = "your_client_id";
private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
private OkHttpClient client = new OkHttpClient();
private Gson gson = new Gson();
public void uploadImage() throws Exception {
File file = new File("website/static/logo-square.png");
RequestBody requestBody = RequestBody.create(MEDIA_TYPE_PNG, file);
Headers headers = new Headers.Builder()
.add("Content-Disposition", "form-data; name=\"image\"")
.build();
Request request = new Request.Builder()
.headers(headers)
.url("https://api.imgur.com/3/image")
.post(requestBody)
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
}
```
在这个类中,我们创建了一个名为uploadImage的方法,该方法使用OkHttpClient发送一个POST请求到Imgur API。我们还使用了Gson库来解析JSON响应。请确保将"your_client_id"替换为您的实际Imgur客户端ID。
以下是根据给定内容重构后的代码:
```java
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
Gist gist = gson.fromJson(response.body().charStream(), Gist.class);
for (Map.Entry
System.out.println(entry.getKey());
System.out.println(entry.getValue().content);
}
}
static class Gist {
Map
}
static class GistFile {
String content;
}
public static void main(String[] args) throws Exception {
CacheResponse cacheResponse = new CacheResponse(new File("cache")); // 设置缓存目录
cacheResponse.run(); // 发起请求并获取响应
}
static class OkHttpClient extends okhttp3.OkHttpClient {
Cache cache;
public OkHttpClient() {
super();
}
public OkHttpClient setCache(Cache cache) {
this.cache = cache;
return this;
}
@Override
public Call newCall(Request request) {
Call call = super.newCall(request);
call.enqueue(new okhttp3.Callback() {
@Override
public void onFailure(Call call, okhttp3.Response response) throws IOException {
if (cache != null && response.code() == okhttp3.StatusCode.SC_NOT_MODIFIED) { // 如果响应状态码为304且缓存存在,则从缓存中获取数据并返回
Response cachedResponse = cache.get(response);
if (cachedResponse != null) {
runSuccess(cachedResponse);
} else { // 如果缓存中不存在该资源,则直接返回失败响应
runFailure(response);
}
} else if (cache != null) { // 如果响应状态码不是304且缓存存在,则将响应结果存入缓存并返回成功响应
Response response1 = call.request().newBuilder().url(response.request().url()).build(); // 从原始请求中构建新的请求以便使用相同的缓存策略
Response response2 = client.newCall(response1).execute(); // 从服务器获取新响应,如果没有修改则返回缓存中的数据,否则更新缓存并返回新响应数据
if (response2 != null && response2.code() == okhttp3.StatusCode.SC_NOT_MODIFIED) { // 如果新响应状态码为304,则从缓存中获取数据并返回成功响应,否则更新缓存并返回新响应数据
Response cachedResponse = cache.get(response1);
if (cachedResponse != null) {
runSuccess(cachedResponse);
} else { // 如果缓存中不存在该资源,则直接返回失败响应,并清空缓存以便下次请求使用新的数据
runFailure(response2);
cache.clear();
}
} else if (response2 != null) { // 如果新响应状态码不是304且有新数据,则清空缓存并将新数据存入缓存并返回成功响应,同时清空缓存以便下次请求使用新的数据
tryToClearCache(response1); // 将原始请求的缓存清空以便下次请求使用新的数据,但不会影响其他请求的缓存数据。这里假设已经实现了tryToClearCache方法。如果没有实现,可以根据实际情况进行调整。
Response cachedResponse = cache.get(response1);
if (cachedResponse != null) {
runSuccess(cachedResponse); // 将新请求的结果存入缓存并返回成功响应,同时清空缓存以便下次请求使用新的数据。这里假设已经实现了runSuccess和runFailure方法。如果没有实现,可以根据实际情况进行调整。
```java
if (!response1.isSuccessful()) throw new IOException(“Unexpected code ” + response1);
String response1Body = response1.body().string();
System.out.println(“Response 1 response: ” + response1);
System.out.println(“Response 1 cache response: ” + response1.cacheResponse());
System.out.println(“Response 1 network response: ” + response1.networkResponse());
Response response2 = client.newCall(request).execute();
if (!response2.isSuccessful()) throw new IOException(“Unexpected code ” + response2);
String response2Body = response2.body().string();
System.out.println(“Response 2 response: ” + response2);
System.out.println(“Response 2 cache response: ” + response2.cacheResponse());
System.out.println(“Response 2 network response: ” + response2.networkResponse());
System.out.println(“Response 2 equals Response 1? ” + response1Body.equals(response2Body));
}
```
在某些情况下,例如用户点击“刷新”按钮后,可能需要跳过缓存并直接从服务器获取数据。要强制完全刷新,请添加no-cache指令:
connection.addRequestProperty("Cache-Control", "no-cache");
如果仅需要强制验证缓存响应是否有效,请使用更高效的max-age=0:
connection.addRequestProperty("Cache-Control", "max-age=0");
强制验证网络响应
有时,我们需要确保网络响应经过验证,可以使用条件GET来实现。条件GET是一个带有查询参数的GET请求,只有当资源内容发生变化时,服务器才会返回新的响应。要实现条件GET,可以在URL中添加一个版本参数,如下所示:
String url = "http://example.com/data?version=1"; // 每次访问时版本号递增 1
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) { // 成功获取数据
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
} else {
// 处理错误情况
}
在某些情况下,您可能希望仅在资源可用时显示它们,而在其他情况下不显示。这可以用于在等待最新数据下载时向应用程序展示一些内容。要限制请求仅针对本地缓存的资源,请添加`only-if-cached`指令:
```java
try {
connection.addRequestProperty("Cache-Control", "only-if-cached");
InputStream cached = connection.getInputStream();
// 资源已经被缓存!显示它
} catch (FileNotFoundException e) {
// 资源未被缓存
}
```
这种技术在以下情况下表现得更好:滞后的响应比没有响应更好。要允许滞后的缓存响应,请使用`max-stale`指令并设置最大滞后时间(以秒为单位):
```java
int maxStale = 60 * 60 * 24 * 28; // 可容忍4周的滞后
connection.addRequestProperty("Cache-Control", "max-stale=" + maxStale);
```
取消一个Call
取消请求的方法有三种:`Call.cancel()`、`RequestBuilder.tag(tag)`和`OkHttpClient.cancel(tag)`。使用其中的一种方法即可取消请求。
```java
import java.io.IOException;
import java.util.concurrent.*;
import okhttp3.*;
public class MainClass {
private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
Request request = new Request.Builder()
.url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay.
.build();
final long startNanos = System.nanoTime();
final Call call = client.newCall(request);
// Schedule a job to cancel the call in 1 second.
executor.schedule(new Runnable() {
@Override
public void run() {
System.out.printf("%.2f Canceling call.%n", (System.nanoTime() - startNanos) / 1e9f);
call.cancel();
System.out.printf("%.2f Canceled call.%n", (System.nanoTime() - startNanos) / 1e9f);
}
}, 1, TimeUnit.SECONDS);
try {
System.out.printf("%.2f Executing call.%n", (System.nanoTime() - startNanos) / 1e9f);
Response response = call.execute();
System.out.printf("%.2f Call was expected to fail, but completed: %s%n", (System.nanoTime() - startNanos) / 1e9f, response);
} catch (IllegalStateException e) {
// If the call is already canceled, this exception will be thrown.
} finally {
// Release the resources held by the call object after it's finished executing or canceled.
call.close();
executor.shutdown();
}
}
}
```
以下是重构后的代码:
```java
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class ConfigureTimeouts {
private final OkHttpClient client;
public ConfigureTimeouts() throws Exception {
client = new OkHttpClient();
client.setConnectTimeout(10, TimeUnit.SECONDS);
client.setWriteTimeout(10, TimeUnit.SECONDS);
client.setReadTimeout(30, TimeUnit.SECONDS);
}
public void run() throws Exception {
Request request = new Request.Builder()
.url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay.
.build();
Response response = client.newCall(request).execute();
System.out.println("Response completed: " + response);
}
}
```
这段代码首先构建了一个请求,其中包含了一个1秒延迟的URL。然后,它尝试使用两个不同的超时时间(500毫秒和3000毫秒)执行此请求。如果请求成功,将输出响应信息;如果失败,将输出异常信息。
处理验证部分,当响应码为401未授权时,返回相应的“WWW-Authenticate”挑战。
这段代码是一个Java程序,用于处理HTTP请求的代理认证。当响应码为407(代理未经授权)时,它会返回"Proxy-Authenticate"挑战。否则,它会返回一个空的挑战列表。
首先,我们创建一个`OkHttpClient`实例:
```java
private final OkHttpClient client = new OkHttpClient();
```
然后,在`run()`方法中,我们设置了一个自定义的认证器,用于处理代理认证:
```java
public void run() throws Exception {
client.setAuthenticator(new Authenticator() {
@Override public Request authenticate(Proxy proxy, Response response) {
System.out.println("Authenticating for response: " + response);
System.out.println("Challenges: " + response.challenges());
String credential = Credentials.basic("jesse", "password1");
return response.request().newBuilder()
.header("Authorization", credential)
.build();
}
@Override public Request authenticateProxy(Proxy proxy, Response response) {
return null; // Null indicates no attempt to authenticate.
}
});
}
```
接下来,我们构建一个请求对象,指定请求的URL:
```java
Request request = new Request.Builder()
.url("http://publicobject.com/secrets/hellosecret.txt")
.build();
```
最后,我们使用`client.newCall(request).execute()`方法发送请求并获取响应。
以下是重构后的代码:
```java
public void exampleMethod() throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://example.com")
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
System.out.println(response.body().string());
}
}
```
在这个例子中,我将整个方法放入了一个类中,并添加了 `throws IOException` 注解以处理可能出现的异常。同时使用 try-with-resources 语句确保资源在执行完毕后被正确关闭。