Android 9开始默认只能访问以HTTPS开头的安全地址,不能直接访问以HTTP开头的网络地址。如果应用仍想访问以HTTP开头的普通地址,就得修改AndroidManifest.xml,给application节点添加如下属性,表示继续使用HTTP明文地址。
使用HttpURLConnection对象
Get方法
public static T get(String url,Class responseClass){
HttpURLConnection connection = null;
try{
URL _url = new URL(url);
connection = (HttpURLConnection)_url.openConnection();
connection.setDoOutput(false);
connection.setDoInput(true);
connection.setRequestMethod("GET");
connection.setUseCaches(false);
connection.setInstanceFollowRedirects(true); //是否自动处理重定向
connection.setConnectTimeout(3000);
connection.connect(); //连接
int code = connection.getResponseCode();
if(code == 200){
String content = StringTools.getStr(connection.getInputStream());
Log.i(TAG,"GET返回:" + content);
}else{
Log.e(TAG,"HTTP错误码:" + code);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
BufferedInputStream bufferedInputStream = new BufferedInputStream(connection.getErrorStream());
byte[] data = new byte[255];
int length = -1;
while ((length = bufferedInputStream.read(data)) != -1){
buffer.write(data,0,length);
}
String errorMsg = new String(buffer.toByteArray(),StandardCharsets.UTF_8);
Log.e(TAG,errorMsg);
}
}catch (Exception e){
Log.e(TAG,e.getMessage(),e);
}finally {
if(connection != null){
connection.disconnect();
}
}
return null;
}
Post方法
public static T post(String url,Object requestObj,Class responseClass){
HttpURLConnection connection = null;
try{
URL _url = new URL(url);
connection = (HttpURLConnection)_url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod("POST");
connection.setUseCaches(false);
connection.setInstanceFollowRedirects(true); //是否自动处理重定向
connection.setRequestProperty("Content-Type","application/json;charset:utf-8");
connection.setConnectTimeout(3000);
connection.connect(); //连接
OutputStream out = connection.getOutputStream();
out.write(JsonTools.toJSONBytes(requestObj));
out.flush();
out.close();
int code = connection.getResponseCode();
if(code == 200){
String content = StringTools.getStr(connection.getInputStream());
Log.i(TAG,"POST返回:" + content);
}else{
Log.e(TAG,"HTTP错误码:" + code);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
BufferedInputStream bufferedInputStream = new BufferedInputStream(connection.getErrorStream());
byte[] data = new byte[255];
int length = -1;
while ((length = bufferedInputStream.read(data)) != -1){
buffer.write(data,0,length);
}
String errorMsg = new String(buffer.toByteArray(),StandardCharsets.UTF_8);
Log.e(TAG,errorMsg);
}
}catch (Exception e){
Log.e(TAG,e.getMessage(),e);
}finally {
if(connection != null){
connection.disconnect();
}
}
return null;
}
通过okhttp调用HTTP接口
添加okhttp包
implementation 'com.squareup.okhttp3:okhttp:4.9.2'
Get方法
// 发起GET方式的HTTP请求
public void doGet() {
OkHttpClient client = new OkHttpClient(); // 创建一个okhttp客户端对象
// 创建一个GET方式的请求结构
Request request = new Request.Builder()
//.get() // 因为OkHttp默认采用get方式,所以这里可以不调get方法
.header("Accept-Language", "zh-CN") // 给http请求添加头部信息
.url(URL_STOCK) // 指定http请求的调用地址
.build();
Call call = client.newCall(request); // 根据请求结构创建调用对象
// 加入HTTP请求队列。异步调用,并设置接口应答的回调方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) { // 请求失败
// 回到主线程操纵界面
runOnUiThread(() -> tv_result.setText("调用股指接口报错:"+e.getMessage()));
}
@Override
public void onResponse(Call call, final Response response) throws IOException { // 请求成功
String resp = response.body().string();
// 回到主线程操纵界面
runOnUiThread(() -> tv_result.setText("调用股指接口返回:\n"+resp));
}
});
}
Post方法
// 发起POST方式的HTTP请求(报文为JSON格式)
public void postJson() {
String username = et_username.getText().toString();
String password = et_password.getText().toString();
String jsonString ="";
try {
JSONObject jsonObject = new JSONObject();
jsonObject.put("username",username);
jsonObject.put("password",password);
jsonString = jsonObject.toString();
} catch (JSONException e) {
e.printStackTrace();
}
// 创建一个POST方式的请求结构
RequestBody body = RequestBody.create(jsonString, MediaType.parse("text/plain;charset=utf-8"));
OkHttpClient client = new OkHttpClient(); // 创建一个okhttp客户端对象
Request request = new Request.Builder().post(body).url(URL_LOGIN).build();
Call call = client.newCall(request);
// 加入HTTP请求队列。异步调用,并设置接口应答的回调方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) { // 请求失败
// 回到主线程操纵界面
runOnUiThread(() -> tv_result.setText("调用登录接口报错:"+e.getMessage()));
}
@Override
public void onResponse(Call call, final Response response) throws IOException { // 请求成功
String resp = response.body().string();
// 回到主线程操纵界面
runOnUiThread(() -> tv_result.setText("调用登录接口返回:\n"+resp));
}
});
}
下载图片方法
public void downloadImage() {
// 创建一个okhttp客户端对象
OkHttpClient client = new OkHttpClient();
// 创建一个GET方式的请求结构
Request request = new Request.Builder().url(URL_IMAGE).build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) { // 请求失败
// 回到主线程操纵界面
runOnUiThread(() -> tv_result.setText("下载网络图片报错:" + e.getMessage()));
}
@Override // 请求成功
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
InputStream is = response.body().byteStream();
// 从返回的输入流中解码获得位图数据
Bitmap bitmap = BitmapFactory.decodeStream(is);
String mediaType = response.body().contentType().toString();
long length = response.body().contentLength();
String desc = String.format("文件类型:%s,文件大小:%d", mediaType, length);
// 回到主线程操纵界面
runOnUiThread(() -> {
tv_result.setText("下载网络图片返回:"+desc);
iv_result.setImageBitmap(bitmap);
});
}
});
}
下载文件方法
public void downloadFile() {
OkHttpClient client = new OkHttpClient(); // 创建一个okhttp客户端对象
// 创建一个GET方式的请求结构
Request request = new Request.Builder().url(URL_APK).build();
Call call = client.newCall(request); // 根据请求结构创建调用对象
// 加入HTTP请求队列。异步调用,并设置接口应答的回调方法
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) { // 请求失败
// 回到主线程操纵界面
runOnUiThread(() -> tv_result.setText("下载网络文件报错:" + e.getMessage()));
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) { // 请求成功
String mediaType = response.body().contentType().toString();
long length = response.body().contentLength();
String desc = String.format("文件类型为%s,文件大小为%d", mediaType, length);
// 回到主线程操纵界面
runOnUiThread(() -> tv_result.setText("下载网络文件返回:" + desc));
String path = String.format("%s/%s.apk",
getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(),
DateUtil.getNowDateTime());
// 下面从返回的输入流中读取字节数据并保存为本地文件
try {
InputStream is = response.body().byteStream();
FileOutputStream fos = new FileOutputStream(path);
byte[] buf = new byte[100 * 1024];
int sum = 0, len = 0;
while ((len = is.read(buf)) !=-1){
fos.write(buf,0,len);
sum += len;
int progress = (int)(sum * 1.0f/length *100);
String detail = String.format("文件保存在%s。已下载%d%%",path,progress);
// 回到主线程操纵界面
runOnUiThread(() -> tv_progress.setText(detail));
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
上传文件方法
private void uploadFile() {
// 创建分段内容的建造器对象
MultipartBody.Builder builder = new MultipartBody.Builder();
String username = et_username.getText().toString();
String password = et_password.getText().toString();
if (!TextUtils.isEmpty(username)) {
// 往建造器对象添加文本格式的分段数据
builder.addFormDataPart("username", username);
builder.addFormDataPart("password", password);
}
for (String path : mPathList) { // 添加多个附件
File file = new File(path); // 根据文件路径创建文件对象
// 往建造器对象添加图像格式的分段数据
builder.addFormDataPart("image", file.getName(),
RequestBody.create(file, MediaType.parse("image/*")));
}
RequestBody body = builder.build(); // 根据建造器生成请求结构
OkHttpClient client = new OkHttpClient(); // 创建一个okhttp客户端对象
// 创建一个POST方式的请求结构
Request request = new Request.Builder().post(body).url(URL_REGISTER).build();
Call call = client.newCall(request); // 根据请求结构创建调用对象
// 加入HTTP请求队列。异步调用,并设置接口应答的回调方法
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) { // 请求失败
// 回到主线程操纵界面
runOnUiThread(() -> tv_result.setText("调用注册接口报错:\n" + e.getMessage()));
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { // 请求成功
String resp = response.body().string();
// 回到主线程操纵界面
runOnUiThread(() -> tv_result.setText("调用注册接口返回:\n" + resp));
}
});
}