Android 发送HTTP GET POST 请求以及通过 MultipartEntityBuilder 上传文件

简介:

折腾了好几天的 HTTP 终于搞定了,经测试正常,不过是初步用例测试用的,因为后面还要修改先把当前版本保存在博客里吧。

其中POST因为涉及多段上传需要导入两个包文件,我用的是最新的 httpmine4.3 发现网上很多 MultipartEntity 相关的文章都是早起版本的,以前的一些方法虽然还可用,但新版本中已经不建议使用了,所以全部使用新的方式 MultipartEntityBuilder 来处理了。

httpmime-4.3.2.jar  
httpcore-4.3.1.jar 


下载地址:http://hc.apache.org/downloads.cgi

有些镜像貌似打不开,页面上可以可以选择国内的 .cn 后缀的域名镜像服务器来下载


如果是 android studio 这里可能会遇到一个问题:Android Duplicate files copied in APK


经测试 POST 对中文处理也是正常的,没有发现乱码

下面是完整代码:

ZHttpRequest.java

package com.ai9475.util;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HTTP;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * Created by ZHOUZ on 14-2-3.
 */
public class ZHttpRequest
{
    protected String url = "";

    protected Map<String, String> headers = null;

    protected int connectionTimeout = 5000;

    protected int soTimeout = 10000;

    protected int statusCode = 200;

    protected String charset = HTTP.UTF_8;

    protected HttpGet httpGet;

    protected HttpPost httpPost;

    protected HttpParams httpParameters;

    protected HttpResponse httpResponse;

    protected HttpClient httpClient;

    protected String inputContent;

    /**
     * 设置当前请求的链接
     *
     * @param url
     * @return
     */
    public ZHttpRequest setUrl(String url)
    {
        this.url = url;
        return this;
    }

    /**
     * 设置请求的 header 信息
     *
     * @param headers
     * @return
     */
    public ZHttpRequest setHeaders(Map headers)
    {
        this.headers = headers;
        return this;
    }

    /**
     * 设置连接超时时间
     *
     * @param timeout 单位(毫秒),默认 5000
     * @return
     */
    public ZHttpRequest setConnectionTimeout(int timeout)
    {
        this.connectionTimeout = timeout;
        return this;
    }

    /**
     * 设置 socket 读取超时时间
     *
     * @param timeout 单位(毫秒),默认 10000
     * @return
     */
    public ZHttpRequest setSoTimeout(int timeout)
    {
        this.soTimeout = timeout;
        return this;
    }

    /**
     * 设置获取内容的编码格式
     *
     * @param charset 默认为 UTF-8
     * @return
     */
    public ZHttpRequest setCharset(String charset)
    {
        this.charset = charset;
        return this;
    }

    /**
     * 获取 HTTP 请求响应信息
     *
     * @return
     */
    public HttpResponse getHttpResponse()
    {
        return this.httpResponse;
    }

    /**
     * 获取 HTTP 客户端连接管理器
     *
     * @return
     */
    public HttpClient getHttpClient()
    {
        return this.httpClient;
    }

    /**
     * 获取请求的状态码
     *
     * @return
     */
    public int getStatusCode()
    {
        return this.statusCode;
    }

    /**
     * 通过 GET 方式请求数据
     *
     * @param url
     * @return
     * @throws IOException
     */
    public String get(String url) throws IOException
    {
        // 设置当前请求的链接
        this.setUrl(url);
        // 实例化 GET 连接
        this.httpGet = new HttpGet(this.url);
        // 自定义配置 header 信息
        this.addHeaders(this.httpGet);
        // 初始化客户端请求
        this.initHttpClient();
        // 发送 HTTP 请求
        this.httpResponse = this.httpClient.execute(this.httpGet);
        // 读取远程数据
        this.getInputStream();
        // 远程请求状态码是否正常
        if (this.statusCode != HttpStatus.SC_OK) {
            return null;
        }
        // 返回全部读取到的字符串
        return this.inputContent;
    }

    public String post(String url, Map<String, String> datas, Map<String, String> files) throws IOException
    {
        this.setUrl(url);
        // 实例化 GET 连接
        this.httpPost = new HttpPost(this.url);
        // 自定义配置 header 信息
        this.addHeaders(this.httpPost);
        // 初始化客户端请求
        this.initHttpClient();
        Iterator iterator = datas.entrySet().iterator();
        MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
        multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
        multipartEntityBuilder.setCharset(Charset.forName(this.charset));
        // 发送的数据
        while (iterator.hasNext()) {
            Map.Entry<String, String> entry = (Map.Entry<String, String>) iterator.next();
            multipartEntityBuilder.addTextBody(entry.getKey(), entry.getValue(), ContentType.create("text/plain", Charset.forName(this.charset)));
        }
        // 发送的文件
        if (files != null) {
            iterator = files.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, String> entry = (Map.Entry<String, String>) iterator.next();
                String path = entry.getValue();
                if ("".equals(path) || path == null) continue;
                File file = new File(entry.getValue());
                multipartEntityBuilder.addBinaryBody(entry.getKey(), file);
            }
        }
        // 生成 HTTP 实体
        HttpEntity httpEntity = multipartEntityBuilder.build();
        // 设置 POST 请求的实体部分
        this.httpPost.setEntity(httpEntity);
        // 发送 HTTP 请求
        this.httpResponse = this.httpClient.execute(this.httpPost);
        // 读取远程数据
        this.getInputStream();
        // 远程请求状态码是否正常
        if (this.statusCode != HttpStatus.SC_OK) {
            return null;
        }
        // 返回全部读取到的字符串
        return this.inputContent.toString();
    }

    /**
     * 为 HTTP 请求添加 header 信息
     *
     * @param request
     */
    protected void addHeaders(HttpRequestBase request)
    {
        if (this.headers != null) {
            Set keys = this.headers.entrySet();
            Iterator iterator = keys.iterator();
            Map.Entry<String, String> entry;
            while (iterator.hasNext()) {
                entry = (Map.Entry<String, String>) iterator.next();
                request.addHeader(entry.getKey().toString(), entry.getValue().toString());
            }
        }
    }

    /**
     * 配置请求参数
     */
    protected void setParams()
    {
        this.httpParameters = new BasicHttpParams();
        this.httpParameters.setParameter("charset", this.charset);
        // 设置 连接请求超时时间
        HttpConnectionParams.setConnectionTimeout(this.httpParameters, this.connectionTimeout);
        // 设置 socket 读取超时时间
        HttpConnectionParams.setSoTimeout(this.httpParameters, this.soTimeout);
    }

    /**
     * 初始化配置客户端请求
     */
    protected void initHttpClient()
    {
        // 配置 HTTP 请求参数
        this.setParams();
        // 开启一个客户端 HTTP 请求
        this.httpClient = new DefaultHttpClient(this.httpParameters);
    }

    /**
     * 读取远程数据
     *
     * @throws IOException
     */
    protected void getInputStream() throws IOException
    {
        // 接收远程输入流
        InputStream inStream = this.httpResponse.getEntity().getContent();
        // 分段读取输入流数据
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buf = new byte[1024];
        int len = -1;
        while ((len = inStream.read(buf)) != -1) {
            baos.write(buf, 0, len);
        }
        // 将数据转换为字符串保存
        this.inputContent = new String(baos.toByteArray());
        // 数据接收完毕退出
        inStream.close();
        // 获取请求返回的状态码
        this.statusCode = this.httpResponse.getStatusLine().getStatusCode();
    }

    /**
     * 关闭连接管理器释放资源
     */
    protected void shutdownHttpClient()
    {
        if (this.httpClient != null && this.httpClient.getConnectionManager() != null) {
            this.httpClient.getConnectionManager().shutdown();
        }
    }
}

MainActivity.java

这个我就只写事件部分了

    public void doClick(View view)
    {
        ZHttpRequest request = new ZHttpRequest();
        String url = "";
        TextView textView = (TextView) findViewById(R.id.showContent);
        String content = "空内容";
        try {
            if (view.getId() == R.id.doGet) {
                url = "http://www.baidu.com";
                content = "GET数据:" + request.get(url);
            } else {
                url = "http://192.168.1.6/test.php";
                HashMap<String, String> datas = new HashMap<String, String>();
                datas.put("p1", "abc");
                datas.put("p2", "中文");
                datas.put("p3", "abc中文cba");
                datas.put("pic", this.picPath);
                HashMap<String, String> files = new HashMap<String, String>();
                files.put("file", this.picPath);
                content = "POST数据:" + request.post(url, datas, files);
            }

        } catch (IOException e) {
            content = "IO异常:" + e.getMessage();
        } catch (Exception e) {
            content = "异常:" + e.getMessage();
        }
        textView.setText(content);
    }

其中的 this.picPath 就是指定的SD卡中的相片路径 String 类型


activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    >
    <ScrollView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        >
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:orientation="vertical"
            >
            <Button
                android:id="@+id/doGet"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:layout_marginBottom="10dp"
                android:text="GET请求"
                android:onClick="doClick"
                />
            <Button
                android:id="@+id/doPost"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:layout_marginBottom="10dp"
                android:text="POST请求"
                android:onClick="doClick"
                />
            <Button
                android:id="@+id/doPhoto"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:layout_marginBottom="10dp"
                android:text="拍照"
                android:onClick="doPhoto"
                />
            <ImageView
                android:id="@+id/showPhoto"
                android:layout_width="fill_parent"
                android:layout_height="250dp"
                android:scaleType="centerCrop"
                android:src="@drawable/add"
                android:layout_marginBottom="10dp"
                />
            <TextView
                android:id="@+id/showContent"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="10dp"
                />
        </LinearLayout>
    </ScrollView>
</LinearLayout>

由于我现在对Java 还不是很熟悉,只看过一些视频教程,实际开发经验不多,我按自己的理解写的注释,不过应该不会有什么太大问题吧,如有错误请指出,谢谢!




目录
相关文章
|
1月前
|
存储 安全 Android开发
"解锁Android权限迷宫:一场惊心动魄的动态权限请求之旅,让你的应用从平凡跃升至用户心尖的宠儿!"
【8月更文挑战第13天】随着Android系统的更新,权限管理变得至关重要。尤其从Android 6.0起,引入了动态权限请求,增强了用户隐私保护并要求开发者实现更精细的权限控制。本文采用问答形式,深入探讨动态权限请求机制与最佳实践,并提供示例代码。首先解释了动态权限的概念及其重要性;接着详述实现步骤:定义、检查、请求权限及处理结果;最后总结了六大最佳实践,包括适时请求、解释原因、提供替代方案、妥善处理拒绝情况、适应权限变更及兼容旧版系统,帮助开发者打造安全易用的应用。
41 0
|
1月前
automate Flow中如何用HTTP,POST的方式发送短信?
automate Flow中如何用HTTP,POST的方式发送短信?
32 2
|
2月前
|
存储 运维 Java
函数计算产品使用问题之如何使用Python的requests库向HTTP服务器发送GET请求
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
|
26天前
|
JavaScript 前端开发 Java
【Azure 环境】各种语言版本或命令,发送HTTP/HTTPS的请求合集
【Azure 环境】各种语言版本或命令,发送HTTP/HTTPS的请求合集
|
2月前
|
安全 Java 网络安全
RestTemplate进行https请求时适配信任证书
RestTemplate进行https请求时适配信任证书
43 3
|
29天前
|
移动开发 JavaScript 前端开发
"解锁axios GET请求新姿势!揭秘如何将数组参数华丽变身,让你的HTTP请求在云端翩翩起舞,挑战技术极限!"
【8月更文挑战第20天】二维码在移动应用中无处不在。本文详述了在UniApp H5项目中实现二维码生成与扫描的方法。通过对比插件`uni-app-qrcode`和库`qrcode-generator`生成二维码,以及使用插件和HTML5 API进行扫描,帮助开发者挑选最佳方案。无论是即插即用的插件还是灵活的JavaScript实现,都能满足不同需求。
25 0
|
2月前
|
测试技术 Python
我们假设要测试一个名为`http://example.com`的网站,并对其进行简单的GET请求性能测试。
我们假设要测试一个名为`http://example.com`的网站,并对其进行简单的GET请求性能测试。
|
2月前
|
消息中间件 调度 Android开发
Android经典面试题之View的post方法和Handler的post方法有什么区别?
本文对比了Android开发中`View.post`与`Handler.post`的使用。`View.post`将任务加入视图关联的消息队列,在视图布局后执行,适合视图操作。`Handler.post`更通用,可调度至特定Handler的线程,不仅限于视图任务。选择方法取决于具体需求和上下文。
39 0
|
3月前
|
安全 网络协议 算法
Android网络基础面试题之HTTPS的工作流程和原理
HTTPS简述 HTTPS基于TCP 443端口,通过CA证书确保服务器身份,使用DH算法协商对称密钥进行加密通信。流程包括TCP握手、证书验证(公钥解密,哈希对比)和数据加密传输(随机数加密,预主密钥,对称加密)。特点是安全但慢,易受特定攻击,且依赖可信的CA。每次请求可能复用Session ID以减少握手。
47 2
|
3月前
|
缓存 安全 JavaScript
全面比较HTTP GET与POST方法
全面比较HTTP GET与POST方法
51 7