一. 前言 1. 关于本地服务器 我的选择是使用自己的电脑作为服务器。我们的手机该如何才能访问的电脑呢?
首先,我们需要将我们的手机和电脑连接在同一个局域网下,手机开热点给电脑连接也可以。
接着,我们需要在终端输入 ifconfig,回车,找到 inet,后面的一串数字就是我们本机的ip地址(ip地址可能变动),比如我的电脑此时的ip就是:192.168.43.43。
2. 操作本地服务器 前往本地服务器的文件夹:/Library/WebServer/Documents,在其中配置我们的后台文件。
我们电脑访问本地服务器的方式是:http://localhost/hello
在手机上我们对应的访问方式是:http://192.168.43.43/hello
3. 实际操作可能出现的问题 程序报错:CLEARTEXT communication to XX not permitted by network security policy
我的第一想法是将 http请求 换成 https请求 ,但是发现就不能在手机上访问我电脑上的服务器了。
百度得到结果:安卓9.0系统出现 CLEARTEXT communication to XX not permitted by network security policy 
解决步骤:
1 2 3 4 5 6 7 8 9 10 11 <?xml version="1.0"  encoding="utf-8" ?> <network-security-config>     <base-config cleartextTrafficPermitted="true"  /> </network-security-config>    <application     ****     android:networkSecurityConfig="@xml/network_config"      ****>       
4. 记得在 AndroidManifest.xml 中配置允许联网的权限 1 2 <uses-permission  android:name ="android.permission.INTERNET" /> 
二. Get请求 1. 配置后台文件 在电脑上的服务器文件夹中创建loginGet.php,填入下面的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?PHP        $name  = $_GET ["name" ];    $pwd  = $_GET ["password" ];        $account  = array (         "name" =>$name ,         "password" =>$pwd ,    );        $result  = array (           "account" =>$account ,           "id" =>"222017602053039" ,           "status" =>3 ,     );        header('Content-Type:application/json' );    echo  json_encode($result ); ?> 
2. 使用Postman查询请求 ① 请求头
② 请求体
3. 发送同步Get请求获取数据 ① 使用
同步Get请求会阻塞主线程,需要开启子线程调用。 
使用GsonFormat插件生成模型类。 
使用Gson第三方库解析JSON数据。 
 
② 代码解释
client执行newCall方法会得到一个Call对象,表示一个新的网络请求。Call对象的execute方法是同步方法,会阻塞当前线程,其返回Response对象。 
通过Response对象的isSuccessful()方法可以判断请求是否成功。 
通过Response的headers()方法可以得到响应头Headers对象,可以通过for循环索引遍历所有的响应头的名称和值。可以通过Headers.name(index)方法获取响应头的名称,通过Headers.value(index)方法获取响应头的值。 
除了索引遍历,通过Headers.get(headerName)方法也可以获取某个响应头的值,比如通过headers.get(“Content-Type”)获得服务器返回给客户端的数据类型。 
但是服务器返回给客户端的响应头中有可能有多个重复名称的响应头,比如在某个请求中,服务器要向客户端设置多个Cookie,那么会写入多个Set-Cookie响应头,且这些Set-Cookie响应头的值是不同的,例如访问百度首页,就有3个Set-Cookie响应头。 
为了解决同时获取多个name相同的响应头的值,Headers中提供了一个public List values(String name)方法,该方法会返回一个List对象,所以此处通过Headers对象的values(‘Set-Cookie’)可以获取全部的Cookie信息,如果调用Headers对象的get(‘Set-Cookie’)方法,那么只会获取最后一条Cookie信息。   
通过Response对象的body()方法可以得到响应体ResponseBody对象,调用其string()方法可以很方便地将响应体中的数据转换为字符串,该方法会将所有的数据放入到内存之中,所以如果数据超过1M,最好不要调用string()方法以避免占用过多内存,这种情况下可以考虑将数据当做Stream流处理。 
 
③ 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 public  class  MainActivity  extends  AppCompatActivity           public  static  final  String TAG = MainActivity.class.getSimpleName();          private  final  OkHttpClient client = new  OkHttpClient();     @Override      protected  void  onCreate (Bundle savedInstanceState)           super .onCreate(savedInstanceState);         setContentView(R.layout.activity_main);         new  Thread(new  Runnable() {             @Override              public  void  run ()                   syncRequestByGet();             }         }).start();     }          public  void  syncRequestByGet ()                   Request.Builder builder = new  Request.Builder();         builder.url("http://192.168.43.43/login/loginGet?name=xl&password=0000" );         Request request = builder.build();         try  {                          Response response = client.newCall(request).execute();                          if  (response.isSuccessful()) {                                  ResponseBody body = response.body();                 String jsonString = body.string();                                                                    Gson gson = new  Gson();                 Student student = gson.fromJson(jsonString, Student.class);                 Log.d(TAG,student.toString());             }else  {                 Log.d(TAG,"响应失败" );             }         } catch  (IOException e) {             e.printStackTrace();             Log.d(TAG,"IO异常:" +e.getMessage());         }     } } Date:Mon, 01  Jun 2020  08:25 :24  GMT Server:Apache/2.4 .41  (Unix) PHP/7.3 .11  Content-Location:loginGet.php Vary:negotiate TCN:choice X-Powered-By:PHP/7.3 .11  Content-Length:77  Keep-Alive:timeout=5 , max=100  Connection:Keep-Alive Content-Type:application/json Student{account=AccountBean{name='xl' , password='0000' }, id='222017602053039' , status=3 } 
4. 发送异步Get请求 ① 代码解释
要想异步执行网络请求,需要执行Call对象的enqueue方法,该方法接收一个okhttp3.Callback对象,enqueue方法不会阻塞当前线程,会新开一个工作线程,让实际的网络请求在工作线程中执行。 
当异步请求成功后,会回调Callback对象的onResponse方法,在该方法中可以获取Response对象。当异步请求失败或者调用了Call对象的cancel方法时,会回调Callback对象的onFailure方法。onResponse和onFailure这两个方法都是在工作线程中执行的。 
 
② 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 public  class  MainActivity  extends  AppCompatActivity           public  static  final  String TAG = MainActivity.class.getSimpleName();          private  final  OkHttpClient client = new  OkHttpClient();     @Override      protected  void  onCreate (Bundle savedInstanceState)           super .onCreate(savedInstanceState);         setContentView(R.layout.activity_main);                  asyncRequestByGet();     }          public  void  asyncRequestByGet ()                   Request.Builder builder = new  Request.Builder();         builder.url("http://192.168.43.43/login/loginGet?name=xl&password=0000" );         Request request = builder.build();         client.newCall(request).enqueue(new  Callback() {             @Override              public  void  onFailure (@NotNull  Call call, @NotNull  IOException e)                   Log.d(TAG,"响应失败" );             }             @Override              public  void  onResponse (@NotNull  Call call, @NotNull  Response response)  throws  IOException                                   if  (response.isSuccessful()) {                                          Headers headers = response.headers();                     for  (int  i = 0 ; i < headers.size(); i++) {                         Log.d(TAG,headers.name(i)+":" +headers.value(i));                     }                                          ResponseBody body = response.body();                     String jsonString = body.string();                                                                                    Gson gson = new  Gson();                     Student student = gson.fromJson(jsonString, Student.class);                     Log.d(TAG,student.toString());                 }else  {                     Log.d(TAG,"响应失败" );                 }             }         });     } } Date:Mon, 01  Jun 2020  08:25 :24  GMT Server:Apache/2.4 .41  (Unix) PHP/7.3 .11  Content-Location:loginGet.php Vary:negotiate TCN:choice X-Powered-By:PHP/7.3 .11  Content-Length:77  Keep-Alive:timeout=5 , max=100  Connection:Keep-Alive Content-Type:application/json Student{account=AccountBean{name='xl' , password='0000' }, id='222017602053039' , status=3 } 
5. 请求头和响应头 典型的HTTP请求头、响应头都是类似于Map<String, String>,每个name对应一个value值。不过像我们之前提到的,也会存在多个name重复的情况,比如相应结果中就有可能存在多个Set-Cookie响应头,同样的,也可能同时存在多个名称一样的请求头。
响应头的读取,我们在上面发送同步Get请求的时候就已经说过了,那么我们如何设置请求头呢?
一般情况下,我们只需要调用header(name, value)方法就可以设置请求头的name和value,调用该方法会确保整个请求头中不会存在多个名称一样的name。如果想添加多个name相同的请求头,应该调用addHeader(name, value)方法,这样可以添加重复name的请求头,其value可以不同,例如如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private  final  OkHttpClient client = new  OkHttpClient();public  void  run ()      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();         System.out.println("Server: "  + response.header("Server" ));     System.out.println("Date: "  + response.header("Date" ));     System.out.println("Vary: "  + response.headers("Vary" )); } 
上面的代码通过addHeader方法添加了两个Accept请求头,且二者的值不同,这样服务器收到客户端发来的请求后,就知道客户端既支持application/json类型的数据,也支持application/vnd.github.v3+json类型的数据。
三. 发送POST请求获取数据 1. 配置后台文件 在电脑上的服务器文件夹中创建loginGet.php,填入下面的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?PHP        $name  = $_POST ["name" ];    $pwd  = $_POST ["password" ];        $account  = array (         "name" =>$name ,         "password" =>$pwd ,    );        $result  = array (           "account" =>$account ,           "id" =>"222017602053039" ,           "status" =>3 ,     );        header('Content-Type:application/json' );    echo  json_encode($result ); ?> 
2. 使用Postman查询请求 ① 请求头
② 请求体
3. 发送POST请求获取数据 ① 代码解释
POST请求无法向GET请求一样直接在URL后面追加键值对信息。 
我们通过在请求的Body中加入form-data类型的信息,达到追加信息的效果。 
 
② 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 public  class  MainActivity  extends  AppCompatActivity           public  static  final  String TAG = MainActivity.class.getSimpleName();          private  final  OkHttpClient client = new  OkHttpClient();     @Override      protected  void  onCreate (Bundle savedInstanceState)           super .onCreate(savedInstanceState);         setContentView(R.layout.activity_main);                  requestByPost();     }          private  void   requestByPost ()                   Request.Builder builder = new  Request.Builder();                  FormBody formBody = new  FormBody.Builder()                 .add("username" , "xl" )                 .add("password" , "0000" )                 .build();                  builder.url("http://192.168.43.43/login/loginGet" );         builder.post(formBody);         Request request = builder.build();         client.newCall(request).enqueue(new  Callback() {             @Override              public  void  onFailure (@NotNull  Call call, @NotNull  IOException e)                   Log.d(TAG,"响应失败" );             }             @Override              public  void  onResponse (@NotNull  Call call, @NotNull  Response response)  throws  IOException                                   if  (response.isSuccessful()) {                                          Headers headers = response.headers();                     for  (int  i = 0 ; i < headers.size(); i++) {                         Log.d(TAG,headers.name(i)+":" +headers.value(i));                     }                                          ResponseBody body = response.body();                     String jsonString = body.string();                                                                                    Gson gson = new  Gson();                     Student student = gson.fromJson(jsonString, Student.class);                     Log.d(TAG,student.toString());                 }else  {                     Log.d(TAG,"响应失败" );                 }             }         });     } } Date:Mon, 01  Jun 2020  09:09:04  GMT Server:Apache/2.4 .41  (Unix) PHP/7.3 .11  X-Powered-By:PHP/7.3 .11  Content-Length:77  Keep-Alive:timeout=5 , max=100  Connection:Keep-Alive Content-Type:application/json Student{account=AccountBean{name='xl' , password='0000' }, id='222017602053039' , status=3 } 
4. 用POST发送表单数据 
Okhttp也提供了MultipartBody类帮助我们完成这个功能。 
MultipartBody继承自RequestBody,也表示请求体。只不过MultipartBody的内部是由多个part组成的,每个part就单独包含了一个RequestBody请求体,所以可以把MultipartBody看成是一个RequestBody的数组,而且可以分别给每个RequestBody单独设置请求头。 
MultipartBody一定要设置setType(MultipartBody.FORM)。 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 private  static  final  String IMGUR_CLIENT_ID = "..." ;private  static  final  MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png" );private  final  OkHttpClient client = new  OkHttpClient();public  void  run ()  throws  Exception               RequestBody requestBody = new  MultipartBody.Builder()         .setType(MultipartBody.FORM)         .addFormDataPart("title" , "Square Logo" )         .addFormDataPart("image" , "logo-square.png" ,             RequestBody.create(MEDIA_TYPE_PNG,             new  File("website/static/logo-square.png" )))         .build();     Request request = new  Request.Builder()         .header("Authorization" , "Client-ID "  + IMGUR_CLIENT_ID)         .url("https://api.imgur.com/3/image" )         .post(requestBody)         .build();     Response response = client.newCall(request).execute();     System.out.println(response.body().string()); } 
四. 发送POST请求上传文件并获取数据 1. 配置后台文件 在电脑上的服务器文件夹中创建upLoad文件夹以及它下面的file,img,video文件夹,upLoadFile.php文件,并填入下面的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 <?PHP        $file  = $_FILES ["file" ];            if ($file ["error" ] > 0 ){                echo  "Error:" .$file ["error" ]."\n" ;    }else {                echo  "上传的文件名:" .$file ["name" ]."\n" ;        echo  "上传的文件类型:" .$file ["type" ]."\n" ;        echo  "上传的文件大小:" .($file ["size" ]/1024 )."Kb\n" ;        echo  "临时路径:" .$file ["tmp_name" ]."\n" ;                        $type  = $file ["type" ];        $path ;        if ($type  == "image/jpeg"  || $type  == "image/png" ){                        $path  = "upLoad/img/" ;        }else  if ($type  == "video/mp4" ){                        $path  = "upLoad/video/" ;        }else  if ($type  == "text/plain" ){                        $path  = "upLoad/file/" ;        }    }       $filePath  = $path .$file ["name" ];        if (file_exists($filePath )){                echo  $file ["name" ]."已存在" ;    }else {                        move_uploaded_file($file ["tmp_name" ],$filePath );                echo  "文件已保存在:" .$filePath ;    } ?> 
2. 使用Postman查询请求 ① 上传文本
② 上传图片
③ 上传视频
4. 代码 ① 上传文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 private  void  uploadTextToServer ()          final  MediaType MEDIA_TYPE = MediaType.parse("text/plain; charset=utf-8" );          final  InputStream is = getResources().openRawResource(R.raw.test);          RequestBody text_request = new  RequestBody() {         @Nullable          @Override          public  MediaType contentType ()               return  MEDIA_TYPE;         }         @Override          public  void  writeTo (@NotNull  BufferedSink bufferedSink)  throws  IOException              bufferedSink.write(getBytesByInputStream(is));         }     };          MultipartBody.Builder multi_builder = new  MultipartBody.Builder();     multi_builder.setType(MultipartBody.FORM);     multi_builder.addFormDataPart("file" ,"test.txt" ,text_request);     RequestBody requestBody = multi_builder.build();          Request.Builder builder = new  Request.Builder();     builder.url("http://192.168.43.43/upLoadFile" );     builder.post(requestBody);     Request request = builder.build();     client.newCall(request).enqueue(new  Callback() {         @Override          public  void  onFailure (@NotNull  Call call, @NotNull  IOException e)               Log.d(TAG,"响应失败" );         }         @Override          public  void  onResponse (@NotNull  Call call, @NotNull  Response response)  throws  IOException                           if  (response.isSuccessful()) {                                  Headers headers = response.headers();                 for  (int  i = 0 ; i < headers.size(); i++) {                     Log.d(TAG,headers.name(i)+":" +headers.value(i));                 }                                  ResponseBody body = response.body();                 String jsonString = body.string();                                                   Log.d(TAG,jsonString);             }else  {                 Log.d(TAG,"响应失败" );             }         }     }); } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Date:Mon, 01  Jun 2020  11 :35 :06  GMT Server:Apache/2.4 .41  (Unix) PHP/7.3 .11  X-Powered-By:PHP/7.3 .11  Content-Length:173  Keep-Alive:timeout=5 , max=100  Connection:Keep-Alive Content-Type:text/html; charset=UTF-8  上传的文件名:test.txt 上传的文件类型:text/plain 上传的文件大小:0. 046875Kb 临时路径:/private /var /tmp/phplJlVE7 文件已保存在:upLoad/file/test.txt 
② 上传图片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 private  void  uploadPictureToServer ()          final  MediaType MEDIA_TYPE = MediaType.parse("image/png" );          final  InputStream is = getResources().openRawResource(R.raw.test_picture);          RequestBody picture_request = new  RequestBody() {         @Nullable          @Override          public  MediaType contentType ()               return  MEDIA_TYPE;         }         @Override          public  void  writeTo (@NotNull  BufferedSink bufferedSink)  throws  IOException              bufferedSink.write(getBytesByInputStream(is));         }     };          MultipartBody.Builder multi_builder = new  MultipartBody.Builder();     multi_builder.setType(MultipartBody.FORM);     multi_builder.addFormDataPart("file" ,"test.png" ,picture_request);     RequestBody requestBody = multi_builder.build();          Request.Builder builder = new  Request.Builder();     builder.url("http://192.168.43.43/upLoadFile" );     builder.post(requestBody);     Request request = builder.build();     client.newCall(request).enqueue(new  Callback() {         @Override          public  void  onFailure (@NotNull  Call call, @NotNull  IOException e)               Log.d(TAG,"响应失败" );         }         @Override          public  void  onResponse (@NotNull  Call call, @NotNull  Response response)  throws  IOException                           if  (response.isSuccessful()) {                                  Headers headers = response.headers();                 for  (int  i = 0 ; i < headers.size(); i++) {                     Log.d(TAG,headers.name(i)+":" +headers.value(i));                 }                                  ResponseBody body = response.body();                 String jsonString = body.string();                                                   Log.d(TAG,jsonString);             }else  {                 Log.d(TAG,"响应失败" );             }         }     }); } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Date:Mon, 01  Jun 2020  12 :49 :54  GMT Server:Apache/2.4 .41  (Unix) PHP/7.3 .11  X-Powered-By:PHP/7.3 .11  Content-Length:177  Keep-Alive:timeout=5 , max=100  Connection:Keep-Alive Content-Type:text/html; charset=UTF-8  上传的文件名:test.png 上传的文件类型:image/png 上传的文件大小:670. 1064453125Kb 临时路径:/private /var /tmp/phpAblC1W 文件已保存在:upLoad/img/test.png 
③ 上传视频
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 private  void  uploadMovieToServer ()          final  MediaType MEDIA_TYPE = MediaType.parse("video/mp4; charset=utf-8" );          final  InputStream is = getResources().openRawResource(R.raw.test_movie);          RequestBody movie_request = new  RequestBody() {         @Nullable          @Override          public  MediaType contentType ()               return  MEDIA_TYPE;         }         @Override          public  void  writeTo (@NotNull  BufferedSink bufferedSink)  throws  IOException              bufferedSink.write(getBytesByInputStream(is));         }     };          MultipartBody.Builder multi_builder = new  MultipartBody.Builder();     multi_builder.setType(MultipartBody.FORM);     multi_builder.addFormDataPart("file" ,"test.mp4" ,movie_request);     RequestBody requestBody = multi_builder.build();          Request.Builder builder = new  Request.Builder();     builder.url("http://192.168.43.43/upLoadFile" );     builder.post(requestBody);     Request request = builder.build();     client.newCall(request).enqueue(new  Callback() {         @Override          public  void  onFailure (@NotNull  Call call, @NotNull  IOException e)               Log.d(TAG,"响应失败" );         }         @Override          public  void  onResponse (@NotNull  Call call, @NotNull  Response response)  throws  IOException                           if  (response.isSuccessful()) {                                  Headers headers = response.headers();                 for  (int  i = 0 ; i < headers.size(); i++) {                     Log.d(TAG,headers.name(i)+":" +headers.value(i));                 }                                  ResponseBody body = response.body();                 String jsonString = body.string();                                                   Log.d(TAG,jsonString);             }else  {                 Log.d(TAG,"响应失败" );             }         }     }); } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Date:Tue, 02  Jun 2020  02 :13 :29  GMT Server:Apache/2.4 .41  (Unix) PHP/7.3 .11  X-Powered-By:PHP/7.3 .11  Content-Length:180  Keep-Alive:timeout=5 , max=100  Connection:Keep-Alive Content-Type:text/html; charset=UTF-8     上传的文件名:test.mp4 上传的文件类型:video/mp4 上传的文件大小:20221. 448242188Kb 临时路径:/private /var /tmp/phpI5C1uB 文件已保存在:upLoad/video/test.mp4 
④ 辅助函数:将输入流->字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 private  byte [] getBytesByInputStream(InputStream is) {    ByteArrayOutputStream bos = new  ByteArrayOutputStream();     byte [] data = new  byte [1024 ];     int  len;     try  {                  while  ((len = is.read(data)) != -1 ){             bos.write(data,0 ,len);         }         bos.flush();         bos.close();     } catch  (IOException e) {         e.printStackTrace();     }     return  bos.toByteArray(); } 
5. 关于上传视频的一点小问题 ①  Error:1 错误
② PHP上传错误类型
假设文件上传字段的名称file,则$_FILES['file']['error']有以下几种错误类型:
UPLOAD_ERR_OK:其值为 0,没有错误发生,文件上传成功。 
UPLOAD_ERR_INI_SIZE:其值为 1,上传的文件超过了 php.ini 中 upload_max_filesize选项限制的值。 
UPLOAD_ERR_FORM_SIZE:其值为 2,上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值。 
UPLOAD_ERR_PARTIAL:其值为 3,文件只有部分被上传。 
UPLOAD_ERR_NO_FILE:其值为 4,没有文件被上传。 
UPLOAD_ERR_NO_TMP_DIR:其值为 6,找不到临时文件夹。PHP 4.3.10 和 PHP 5.0.3 引进。 
UPLOAD_ERR_CANT_WRITE:其值为 7,文件写入失败。PHP 5.1.0 引进。 
 
③ 改正方式
修改:php.ini 中 upload_max_filesize 选项限制的值。
问题1:Mac OS X中没有默认的php.ini文件
使用对应的模版文件php.ini.default,修改upload_max_filesize,然后执行以下的拷贝命令即可。
1 sudo cp /private /etc/php.ini.default  /private /etc/php.ini   
问题2:仍然不成功的情况
php默认的 post_max_size 为 2M。如果 POST 数据尺寸大于 post_max_size,页面不会给出提醒,文件也上传失败 。
按照问题1的方式修改 post_max_size。
五. 发送GET请求下载图片 1. 使用Postman查询请求 
2. 代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 private  void  downloadPicture ()          Request.Builder builder = new  Request.Builder();     builder.url("http://192.168.43.43/upLoad/img/test.png" );     Request request = builder.build();     client.newCall(request).enqueue(new  Callback() {         @Override          public  void  onFailure (@NotNull  Call call, @NotNull  IOException e)               Log.d(TAG,"响应失败" );         }         @Override          public  void  onResponse (@NotNull  Call call, @NotNull  Response response)  throws  IOException                           if  (response.isSuccessful()) {                                  Headers headers = response.headers();                 for  (int  i = 0 ; i < headers.size(); i++) {                     Log.d(TAG,headers.name(i)+":" +headers.value(i));                 }                                  ResponseBody body = response.body();                                  InputStream is = body.byteStream();                                                   final  Bitmap bitmap = BitmapFactory.decodeStream(is);                                  runOnUiThread(new  Runnable() {                     @Override                      public  void  run ()                           imageView.setImageBitmap(bitmap);                     }                 });                                  is.close();             }else  {                 Log.d(TAG,"响应失败" );             }         }     }); } 
六. 源码 OkHttpTest 
参考文章 界面提交方式-Get和Post 
上传和下载视频到本地服务器 
文加图, 理解Http请求与响应 
OkHttp使用详解 
Android 网络(三) HttpURLConnection OkHttp 
修改php文件上传的大小限制upload_max_filesize 
PHP使用之修改php.ini 配置文件(Mac)