網(wǎng)絡(luò)協(xié)議的知識(shí)湖雹,數(shù)據(jù)在Internet上傳輸,一般通過(guò)三種協(xié)議來(lái)實(shí)現(xiàn)發(fā)送信息和實(shí)現(xiàn):
HTTP協(xié)議程剥,也是在工作中最常用的劝枣,是建立在TCP/IP基礎(chǔ)上實(shí)現(xiàn)的。
FTP協(xié)議织鲸。
TCP/IP協(xié)議舔腾,它也是最低層的協(xié)議,其它的方式必須要通過(guò)它搂擦,但是想要實(shí)現(xiàn)這種協(xié)議必須要實(shí)現(xiàn)socket編程稳诚,這種方法是用來(lái)上傳一些比較大的文件,視頻瀑踢,進(jìn)行斷電續(xù)傳的操作扳还。
HTTP協(xié)議
下面詳細(xì)講解一下HTTP協(xié)議,因?yàn)镠TTP是無(wú)狀態(tài)的協(xié)議橱夭,所以服務(wù)端并不記錄客戶(hù)端之前發(fā)送信息氨距,一碼歸一碼,所以HTTP協(xié)議使用報(bào)文頭的形式記錄狀態(tài)棘劣,一般分為請(qǐng)求報(bào)文和響應(yīng)報(bào)文俏让。一般用戶(hù)使用瀏覽器訪問(wèn)網(wǎng)頁(yè),是無(wú)需關(guān)心HTTP請(qǐng)求的報(bào)文頭的茬暇,因?yàn)殚_(kāi)發(fā)人員在瀏覽器中已經(jīng)幫忙處理了首昔,但是當(dāng)進(jìn)行開(kāi)發(fā)工作的時(shí)候,這些是必須要了解的糙俗。
對(duì)于報(bào)文勒奇,一般關(guān)心請(qǐng)求方式,是GET或者是POST巧骚;請(qǐng)求數(shù)據(jù)類(lèi)型赊颠,是文本還是音頻格二;數(shù)據(jù)的編碼格式,一般用utf-8巨税;發(fā)送的數(shù)據(jù)長(zhǎng)度蟋定;響應(yīng)返回碼,一般200為成功草添,其他響應(yīng)碼都是有問(wèn)題驶兜。具體了解還是看看上面推薦的博客。
HTTP/1.1協(xié)議中一共定義了八種方法(有時(shí)也叫“動(dòng)作”)來(lái)表明Request-URI指定的資源的不同操作方式远寸,但是一般常用的就是GET和POST方式抄淑。
這里簡(jiǎn)單說(shuō)一下GET方式和POST方式的差別:
GET是從服務(wù)器上獲取數(shù)據(jù),POST是向服務(wù)器傳送數(shù)據(jù)驰后。
在客戶(hù)端肆资,GET方式在通過(guò)URL提交數(shù)據(jù),數(shù)據(jù)在URL中可以看到灶芝;POST方式郑原,數(shù)據(jù)放在HTML HEADER內(nèi)提交。
對(duì)于GET方式夜涕,服務(wù)器端用Request.QueryString獲取變量的值犯犁,對(duì)于POST方式,服務(wù)器用Request.Form獲取提交的數(shù)據(jù)女器。
GET方式提交的數(shù)據(jù)不能大于2KB(主要是URL長(zhǎng)度限制)酸役,而POST則沒(méi)有此限制。
安全性問(wèn)題驾胆。正如2中提到涣澡,使用GET的時(shí)候,參數(shù)會(huì)顯示在地址欄上丧诺,而POST不會(huì)入桂。所以,如果這些數(shù)據(jù)是中文數(shù)據(jù)而且是非敏感數(shù)據(jù)驳阎,那么使用GET事格;如果用戶(hù)輸入的數(shù)據(jù)不是中文字符而且包含敏感數(shù)據(jù),那么還是使用POST為好搞隐。
Java中使用HTTP
下面通過(guò)兩個(gè)例子來(lái)分別講解一下GET和POST在Java中的使用,如果在Java中需要使用HTTP協(xié)議進(jìn)行訪問(wèn)远搪,一般通過(guò)HttpURLConnection類(lèi)來(lái)實(shí)現(xiàn)劣纲。
HttpURLConnection繼承了URLConnection,所以在URLConnection的基礎(chǔ)上進(jìn)一步改進(jìn)谁鳍,增加了一些用于操作HTTP資源的便捷方法癞季。Java中HttpURLConnection對(duì)象通過(guò)URL.openConnection()方法來(lái)獲得劫瞳,需要進(jìn)行強(qiáng)制轉(zhuǎn)換。先來(lái)介紹幾個(gè)HttpURLConnection的常用方法:
void?setConnectTimeout(int timeout):設(shè)置連接超時(shí)時(shí)長(zhǎng)绷柒,如果超過(guò)timeout時(shí)長(zhǎng)志于,則放棄連接,單位以毫秒計(jì)算废睦。
void?setDoInput(boolean newValue) :標(biāo)志是否允許輸入伺绽。
void?setDoOutput(boolean newValue):標(biāo)志是否允許輸出。
String getRequestMethod():獲取發(fā)送請(qǐng)求的方法嗜湃。
int getResponseCode():獲取服務(wù)器的響應(yīng)碼奈应。
void setRequestMethod(String method):設(shè)置發(fā)送請(qǐng)求的方法。
void setRequestProperty(String field,String newValue):設(shè)置請(qǐng)求報(bào)文頭购披,并且只對(duì)當(dāng)前HttpURLConnection有效杖挣。
FutureTask可用于異步獲取執(zhí)行結(jié)果或取消執(zhí)行任務(wù)的場(chǎng)景。通過(guò)傳入Runnable或者Callable的任務(wù)給FutureTask刚陡,直接調(diào)用其run方法或者放入線程池執(zhí)行惩妇,之后可以在外部通過(guò)FutureTask的get方法異步獲取執(zhí)行結(jié)果,因此筐乳,F(xiàn)utureTask非常適合用于耗時(shí)的計(jì)算歌殃,主線程可以在完成自己的任務(wù)后,再去獲取結(jié)果哥童。另外挺份,F(xiàn)utureTask還可以確保即使調(diào)用了多次run方法,它都只會(huì)執(zhí)行一次Runnable或者Callable任務(wù)贮懈,或者通過(guò)cancel取消FutureTask的執(zhí)行等匀泊。
因?yàn)榭紤]到連接時(shí)間比較長(zhǎng),采用FutureTask
GET方式
public static String get(final String url) throws Exception {
??????? String r = null;
??????? FutureTask<String> task = new FutureTask<>(new Callable<String>() {
??????????? @Override
??????????? public String call() throws Exception {
??????????????? BufferedReader bufferedReader = null;
??????????????? String result = null;
??????????????? try {
??????????????????? URL realUrl = new URL(url);
??????????????????? HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
??????????????????? if (connection instanceof HttpsURLConnection) {
??????????????????????? SSLContext sslContext = SSLContextUtil.getSSLContext(mContext, "證書(shū)");
??????????????????????? if (sslContext != null) {
??????????????????????????? SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
??????????????????????????? ((HttpsURLConnection) connection).setSSLSocketFactory(sslSocketFactory);
??????????????????????? }
??????????????????? }
connection.connect();
//向本地寫(xiě)入數(shù)據(jù)
??????????????????? bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
??????????????????? String line;
??????????????????? StringBuffer sb = new StringBuffer();
??????????????????? while ((line = bufferedReader.readLine()) != null) {
??????????????????????? sb.append(line);
??????????????????? }
??????????????????? result = sb.toString();
??????????????? } catch (IOException e) {
???????????????????
??????????????? } catch (Exception e) {
??????????????????
//最終要關(guān)閉流
????????????? } finally {
??????????????????? if (bufferedReader != null) {
??????????????????????? try {
??????????????????????????? bufferedReader.close();
??????????????????????? } catch (IOException e) {
???????????????????????????
??????????????????????? }
??????????????????? }
??????????????? }
??????????????? return result;
??????????? }
??????? });
??????? new Thread(task).start();
???? try {
??????????? r = task.get();
??????? } catch (InterruptedException e) {
???????????
??????? } catch (ExecutionException e) {
??????????
??????? }
??????? return r;
??? }
POST方式
public static String post(final String url, final Map<String, Object> params) throws Exception {
??????? String r = null;
??????? final String TAG = "PostTag";
??????? FutureTask<String> task = new FutureTask<>(new Callable<String>() {
??????????? @Override
??????????? public String call() throws Exception {
??????????????? String result = null;
??????????????? BufferedReader bufferedReader = null
??????????????? PrintWriter out = null;
??????????????? LogUtil.d(TAG, "call: start ");
??????????????? try {
???????????????
??????????????????? String line = null;
??????????????????? StringBuffer sb = new StringBuffer();
??????????????????? URL realUrl = new URL(url);
??????????????????? int outTime = 5 * 1000; //超時(shí)設(shè)置
??????????????????? URLConnection connection = realUrl.openConnection();
//添加證書(shū)
??????????????????? if (connection instanceof HttpsURLConnection) {
??????????????????????? SSLContext sslContext = SSLContextUtil.getSSLContext(mContext, "證書(shū)");
??????????????????????? if (sslContext != null) {
??????????????????????????? SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
??????????????????????????? ((HttpsURLConnection) connection).setSSLSocketFactory(sslSocketFactory);
??????????????????????? }
??????????????????? }
//添加證書(shū)
////設(shè)置請(qǐng)求報(bào)文頭朵你,設(shè)定請(qǐng)求數(shù)據(jù)類(lèi)型
??????????????????? connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
??????????????????? connection.setConnectTimeout(outTime);
//設(shè)置允許輸入輸出
??????????????????? connection.setDoOutput(true);
??????????????????? connection.setDoInput(true);
??????????????????? connection.setUseCaches(false);
??????????????????? out = new PrintWriter(connection.getOutputStream());
??????????????????? out.print(getParams(params));
???????????????????
??????????????????? out.flush();
//把服務(wù)端返回的輸入流轉(zhuǎn)換成字符串格式
??????????????????? bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
??????????????????? while ((line = bufferedReader.readLine()) != null) {
??????????????????????? sb.append(line);
??????????????????????? Log.d(TAG, "call: while ");
??????????????????? }
?????????????????? result = sb.toString(); //結(jié)果返回
??????????????????? Log.d(TAG, "result: " + result);
??????????????? } catch (IOException e) {
??????????????????
??????????????????? throw e;
??????????????? } finally {
??????????????????? if (bufferedReader != null) {
??????????????????????? try {
??????????????????????????? bufferedReader.close();
??????????????????????? } catch (IOException e) {
??????????????????????????? Log.e(TAG, e.getCause(), "");
??????????????????????? }
??????????????????? }
??????????????? }
??????????????? return result;
??????????? }
??????? });
????? new Thread(task).start();
??????? try {
??????????? r = task.get();
??????? } catch (InterruptedException e) {
??????????? Log.e(TAG, e.getCause(), "");
??????????? Log.d(TAG, "post: " + "InterruptedException");
??????? } catch (ExecutionException e) {
??????????? Log.e(TAG, e.getCause(), "");
??????????? Log.d(TAG, "post: " + "ExecutionException");
??????? } catch (Exception e) {
??????????? Log.e(TAG, e.getCause(), "");
??????????? Log.d(TAG, "post: " + "");
??????? }
??????? return r;
??? }
//將請(qǐng)求參數(shù)轉(zhuǎn)換格式各聘,//請(qǐng)求的參數(shù)之間使用&分割。
?? private static String getParams(Map<String, Object> params) {
??????? StringBuffer sb = new StringBuffer();
??????? if (params != null) {
??????????? for (String key : params.keySet()) {
??????????????? sb.append(key).append("=").append(params.get(key).toString()).append("&");
??????????? }
??????????? if (sb.indexOf("&") == sb.length() - 1) {
??????????????? sb.deleteCharAt(sb.length() - 1);
??????????? }
??????? }
??????? return sb.toString();
??? }