Android开源:Http/Https 组件

Warran 8年前
   <h2>android-major-https</h2>    <p>android-major-https是一款 Android 上的 Http/Https 组件。内部使用 <strong> Volley </strong> 作为底层 Http 组件。主要特性有:</p>    <ul>     <li>支持 GET、 POST、 DELETE、 PUT、 HEAD 等;</li>     <li>支持 Http、 <strong>Https</strong> ;</li>     <li>对 Https 支持 <strong>自定义证书验证</strong> 、 <strong>域名验证</strong> 等;</li>     <li>支持 Text、 Binary、 Json、 文件下载、 文件上传等;</li>     <li>支持 Json 自动解析为 POJO;</li>     <li>接口简洁易用,支持 Java8 <strong>Lambda</strong> 。</li>    </ul>    <h3>1、Gradle 配置</h3>    <pre>  <code class="language-java">compile 'com.jungle.majorhttp:major-http:1.0.0'</code></pre>    <h3>2、使用方法</h3>    <p>使用预定义的各种 Model 来加载 URL,通过各种方法来设置加载参数。最后使用 <strong> load </strong> 或 <strong> loadWithProgress </strong> 来加载请求。</p>    <p>load只是在后台加载,界面上没有任何表现。 <strong>loadWithProgress</strong> 在加载的时候会弹出一个加载展示 Dialog(该对话框样式可自定义),并在后台加载。请求返回后,将自动关闭 Dialog。</p>    <p>预定义的 Model 列表如下:</p>    <table>     <thead>      <tr>       <th>请求类型</th>       <th>Model</th>       <th>数据结果</th>      </tr>     </thead>     <tbody>      <tr>       <td>文本请求</td>       <td>TextRequestModel</td>       <td>String</td>      </tr>      <tr>       <td>Json POJO 请求</td>       <td>JsonRequestModel</td>       <td>POJO Java 对象</td>      </tr>      <tr>       <td>二进制数据请求</td>       <td>BinaryRequestModel</td>       <td>byte[]</td>      </tr>      <tr>       <td>数据下载(获取)请求</td>       <td>DownloadRequestModel</td>       <td>byte[]</td>      </tr>      <tr>       <td>文件下载请求</td>       <td>DownloadFileRequestModel</td>       <td>String 下载好的文件路径</td>      </tr>      <tr>       <td>上传请求</td>       <td>UploadRequestModel</td>       <td>String 服务器返回的上传结果</td>      </tr>      <tr>       <td>JsonObject 请求</td>       <td>JsonObjectRequestModel</td>       <td>JSONObject</td>      </tr>      <tr>       <td>JsonArray 请求</td>       <td>JsonArrayRequestModel</td>       <td>JSONArray</td>      </tr>     </tbody>    </table>    <p>具体代码示例如下:</p>    <pre>  <code class="language-java">private static final String DEMO_WEB_URL =          "https://www.zhihu.com";    private static final String DEMO_JSON_URL =          "https://raw.githubusercontent.com/arnozhang/major-http/master/docs/demo.json";    private static final String DEMO_UPLOAD_URL =          "https://raw.githubusercontent.com/upload_test";      private void showError(int errorCode, String message) {      // ...  }</code></pre>    <ul>     <li>文本请求,使用 <strong> TextRequestModel </strong> :</li>    </ul>    <pre>  <code class="language-java">TextRequestModel          .newModel()          .url(DEMO_WEB_URL)          .success(new ModelSuccessListener<String>() {              @Override              public void onSuccess(NetworkResp networkResp, String response) {                  TextViewerActivity.start(getContext(), response);              }          })          .error(new ModelErrorListener() {              @Override              public void onError(int errorCode, String message) {                  showError(errorCode, message);              }          })          .load();</code></pre>    <p>或者只用一个统一的 Listener:</p>    <pre>  <code class="language-java">TextRequestModel          .newModel()          .url(DEMO_WEB_URL)          .load(new ModelListener<String>() {              @Override              public void onSuccess(NetworkResp networkResp, String response) {                  TextViewerActivity.start(getContext(), response);              }                @Override              public void onError(int errorCode, String message) {                  showError(errorCode, message);              }          });</code></pre>    <p>如果你支持 <strong>Java8</strong> ,你还可以使用 <strong>lambda</strong> 表达式。可以看出使用 lambda 后,整个语法简洁了很多:</p>    <pre>  <code class="language-java">TextRequestModel          .newModel()          .url(DEMO_WEB_URL)          .success((networkResp, response) -> TextViewerActivity.start(getContext(), response))          .error(this::showError)          .load();</code></pre>    <ul>     <li>Json POJO 请求,使用 <strong> JsonRequestModel </strong> :</li>    </ul>    <pre>  <code class="language-java">public class GithubUserInfo {        public static class Project {          public String name;          public String url;      }        public String uid;      public String userName;      public String site;      public String[] languages;      public List<Project> projects;  }    JsonRequestModel          .newModel(GithubUserInfo.class)          .url(DEMO_JSON_URL)          .method(ModelMethod.GET)          .load(new BizModelListener<GithubUserInfo>() {              @Override              public void onSuccess(NetworkResp networkResp, GithubUserInfo response) {                  String info = JSON.toJSONString(response, SerializerFeature.PrettyFormat);                  info = "Load Json object success!\n\n" + info;                  TextViewerActivity.start(getContext(), info);              }                @Override              public void onError(int errorCode, String message) {                  showError(errorCode, message);              }          });</code></pre>    <p>Json 解析为 POJO 的过程,使用第三方 Json 库 <strong> fastjson </strong> 。</p>    <ul>     <li>文件下载请求,使用 <strong> DownloadFileRequestModel </strong> :</li>    </ul>    <pre>  <code class="language-java">final String file = getDemoFilePath();  String loadingText = String.format("Downloading File: \n%s", file);    DownloadFileRequestModel          .newModel()          .url(DEMO_JSON_URL)          .filePath(file)          .lifeListener(new ModelLoadLifeListener<DownloadFileRequestModel>() {              @Override              public void onBeforeLoad(DownloadFileRequestModel model) {                  ActivityCompat.requestPermissions(context,                          new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 100);              }          })          .loadWithProgress(getContext(), loadingText, new BizModelListener<String>() {              @Override              public void onSuccess(NetworkResp networkResp, String response) {                  Toast.makeText(getContext(), String.format(                          "Download file SUCCESS! file = %s.", file), Toast.LENGTH_SHORT).show();              }                @Override              public void onError(int errorCode, String message) {                  showError(errorCode, message);              }          });</code></pre>    <ul>     <li>文件上传请求,使用 <strong> UploadRequestModel </strong> :</li>    </ul>    <pre>  <code class="language-java">final String file = getDemoFilePath();    UploadRequestModel          .newModel()          .url(DEMO_UPLOAD_URL)          .addFormItem(file)          .loadWithProgress(this, "Uploading...", new BizModelListener<String>() {              @Override              public void onSuccess(NetworkResp networkResp, String response) {                  Toast.makeText(getContext(), String.format(                          "Upload file SUCCESS! file = %s.", file), Toast.LENGTH_SHORT).show();              }                @Override              public void onError(int errorCode, String message) {                  showError(errorCode, message);              }          });</code></pre>    <h3>3、Http / Https 支持</h3>    <p>通过 <strong> MajorHttpClient </strong> 这个组件可以配置 Http / Https:</p>    <table>     <thead>      <tr>       <th>方法</th>       <th>解释</th>      </tr>     </thead>     <tbody>      <tr>       <td>setRequestQueueFactory</td>       <td>设置请求队列 Factory</td>      </tr>      <tr>       <td>setDefaultTimeoutMilliseconds</td>       <td>设置基础请求的超时时间</td>      </tr>      <tr>       <td>setUploadTimeoutMilliseconds</td>       <td>设置上传类请求的超时时间</td>      </tr>      <tr>       <td>setExtraHeadersFiller</td>       <td>为每个请求设置额外的 Header 填充回调(具体项目中比如动态填入 uid、ticket 等等)</td>      </tr>     </tbody>    </table>    <p>3.1、Http 支持</p>    <pre>  <code class="language-java">MajorHttpClient.getDefault().setRequestQueueFactory(new HttpRequestQueueFactory(context));</code></pre>    <p>3.2、Https 支持</p>    <pre>  <code class="language-java">String[] certs = {          "zhihu.cer",          "github.cer",          "githubusercontent.cer"  };    String[] domains = {          "zhihu.com",          "github.com",          "githubusercontent.com"  };    HttpsRequestQueueFactory factory = new HttpsRequestQueueFactory(this, certs);  factory.setHostnameVerifier(new HttpsUtils.DomainHostnameVerifier(domains));    MajorHttpClient.getDefault().setRequestQueueFactory(factory);</code></pre>    <p>Https 可以将证书文件放在 <strong>assets</strong> 文件夹下,或者放在 <strong>res/raw</strong> 文件夹下,然后在代码中创建相应的 <strong> HttpsRequestQueueFactory </strong> 。通过 <strong> HttpsRequestQueueFactory.setHostnameVerifier </strong> 可以设置域名验证。</p>    <p>3.3、Https 验证失败异常</p>    <p>如果请求的 URL <strong>证书验证</strong> 不通过,则错误如下:</p>    <pre>  <code class="language-java">com.android.volley.NoConnectionError:      javax.net.ssl.SSLHandshakeException:          java.security.cert.CertPathValidatorException:              Trust anchor for certification path not found..</code></pre>    <p>如果请求的 URL <strong>域名验证</strong> 不通过,则错误如下:</p>    <pre>  <code class="language-java">com.android.volley.NoConnectionError:      javax.net.ssl.SSLPeerUnverifiedException: Hostname github.com not verified:              certificate: sha1/1O6dKmcSs2FMJy0ViwT8yMoIoLY=              DN: CN=github.com,O=GitHub\, Inc.,L=San Francisco,ST=California,C=US,2.5.4.17=#13053934313037,STREET=88 Colin P Kelly\, Jr Street,2.5.4.5=#130735313537353530,1.3.6.1.4.1.311.60.2.1.2=#130844656c6177617265,1.3.6.1.4.1.311.60.2.1.3=#13025553,2.5.4.15=#0c1450726976617465204f7267616e697a6174696f6e              subjectAltNames: [github.com, www.github.com].</code></pre>    <h2>License</h2>    <pre>  <code class="language-java">/**   * Android Jungle-Major-Http framework project.   *   * Copyright 2016 Arno Zhang <zyfgood12@163.com>   *   * Licensed under the Apache License, Version 2.0 (the "License");   * you may not use this file except in compliance with the License.   * You may obtain a copy of the License at   *   *      http://www.apache.org/licenses/LICENSE-2.0   *   * Unless required by applicable law or agreed to in writing, software   * distributed under the License is distributed on an "AS IS" BASIS,   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   * See the License for the specific language governing permissions and   * limitations under the License.   */</code></pre>    <p> </p>    <p> </p>    <p> </p>