java網絡編程(2):HTTP



第0章:簡介

       超文本傳輸協議 (HTTP-Hypertext transfer protocol) 是一種詳細規定了瀏覽器和萬維網服務器之間互相通信的規則,通過因特網傳送萬維網文檔的數據傳送協議。HTTP目前協議的版本是1.1.HTTP是一種無狀態的協議,無狀態是指Web瀏覽器和Web服務器之間不需要建立持久的連接,這意味着當一個客戶端向服務器端發出請求,然後Web服務器返回響應(response),連接就被關閉了,在服務器端不保留連接的有關信息.HTTP遵循請求(Request)/應答(Response)模型。Web瀏覽器向Web服務器發送請求,Web服務器處理請求並返回適當的應答。所有HTTP連接都被構造成一套請求和應答。

第0節:HTTP通信機制

(1)    建立TCP連接
HTTP工作開始之前,Web瀏覽器首先要通過網絡與Web服務器建立連接,該連接是通過TCP來完成的,該協議與IP協議共同構建Internet,即著名的TCP/IP協議族,因此Internet又被稱作是TCP/IP網絡。HTTP是比TCP更高層次的應用層協議,根據規則,只有低層協議建立之後才能,才能進行更層協議的連接,因此,首先要建立TCP連接,一般TCP連接的端口號是80
(2)    Web瀏覽器向Web服務器發送請求命令
一旦建立了TCP連接,Web瀏覽器就會向Web服務器發送請求命令
例如:GET/sample/hello.jsp HTTP/1.1
(3)    Web瀏覽器發送請求頭信息
瀏覽器發送其請求命令之後,還要以頭信息的形式向Web服務器發送一些別的信息,之後瀏覽器發送了一空白行來通知服務器,它已經結束了該頭信息的發送。
(4)    Web服務器應答
客戶機向服務器發出請求後,服務器會客戶機回送應答,
HTTP/1.1 200 OK
應答的第一部分是協議的版本號和應答狀態碼
(5)    Web服務器發送應答頭信息
正如客戶端會隨同請求發送關於自身的信息一樣,服務器也會隨同應答向用戶發送關於它自己的數據及被請求的文檔。
(6)    Web服務器向瀏覽器發送數據
Web服務器向瀏覽器發送頭信息後,它會發送一個空白行來表示頭信息的發送到此爲結束,接着,它就以Content-Type應答頭信息所描述的格式發送用戶所請求的實際數據
(7)    Web服務器關閉TCP連接
一般情況下,一旦Web服務器向瀏覽器發送了請求數據,它就要關閉TCP連接,然後如果瀏覽器或者服務器在其頭信息加入了這行代碼
Connection:keep-alive
TCP連接在發送後將仍然保持打開狀態,於是,瀏覽器可以繼續通過相同的連接發送請求。保持連接節省了爲每個請求建立新連接所需的時間,還節約了網絡帶寬。

第1節:HTTP請求格式

當瀏覽器向Web服務器發出請求時,它向服務器傳遞了一個數據塊,也就是請求信息,HTTP請求信息由3部分組成:
l   請求方法URI協議/版本
l   請求頭(Request Header)
l
   請求正文下面是一個HTTP請求的例子:
GET/sample.jspHTTP/1.1
Accept:image/gif.image/jpeg,*/*
Accept-Language:zh-cn
Connection:Keep-Alive
Host:localhost
User-Agent:Mozila/4.0(compatible;MSIE5.01;Window NT5.0)
Accept-Encoding:gzip,deflate
 
username=jinqiao&password=1234
 
(1)       請求方法URI協議/版本
請求的第一行是“方法URL議/版本”:GET/sample.jsp HTTP/1.1
以上代碼中“GET”代表請求方法,“/sample.jsp”表示URI,“HTTP/1.1代表協議和協議的版本。
根據HTTP標準,HTTP請求可以使用多種請求方法。例如:HTTP1.1支持7種請求方法:GET、POST、HEAD、OPTIONS、PUT、DELETE和TARCE。在Internet應用中,最常用的方法是GET和POST。
URL完整地指定了要訪問的網絡資源,通常只要給出相對於服務器的根目錄的相對目錄即可,因此總是以“/”開頭,最後,協議版本聲明瞭通信過程中使用HTTP的版本。
2) 請求頭(Request Header)
請求頭包含許多有關的客戶端環境和請求正文的有用信息。例如,請求頭可以聲明瀏覽器所用的語言,請求正文的長度等。
Accept:image/gif.image/jpeg.*/*
Accept-Language:zh-cn
Connection:Keep-Alive
Host:localhost
User-Agent:Mozila/4.0(compatible:MSIE5.01:Windows NT5.0)
Accept-Encoding:gzip,deflate.
3) 請求正文
請求頭和請求正文之間是一個空行,這個行非常重要,它表示請求頭已經結束,接下來的是請求正文。請求正文中可以包含客戶提交的查詢字符串信息:
username=jinqiao&password=1234
在以上的例子的HTTP請求中,請求的正文只有一行內容。當然,在實際應用中,HTTP請求正文可以包含更多的內容。
HTTP請求方法我這裏只討論GET方法與POST方法
l         GET方法
GET方法是默認的HTTP請求方法,我們日常用GET方法來提交表單數據,然而用GET方法提交的表單數據只經過了簡單的編碼,同時它將作爲URL的一部分向Web服務器發送,因此,如果使用GET方法來提交表單數據就存在着安全隱患上。例如
從上面的URL請求中,很容易就可以辯認出表單提交的內容。(?之後的內容)另外由於GET方法提交的數據是作爲URL請求的一部分所以提交的數據量不能太大
l         POST方法
POST方法是GET方法的一個替代方法,它主要是向Web服務器提交表單數據,尤其是大批量的數據。POST方法克服了GET方法的一些缺點。通過POST方法提交表單數據時,數據不是作爲URL請求的一部分而是作爲標準數據傳送給Web服務器,這就克服了GET方法中的信息無法保密和數據量太小的缺點。因此,出於安全的考慮以及對用戶隱私的尊重,通常表單提交時採用POST方法。

第2節:HTTP應答格式

從編程的角度來講,如果用戶通過GET方法提交數據,則數據存放在QUERY_STRING環境變量中,而POST方法提交的數據則可以從標準輸入流中獲取。

HTTP應答HTTP請求相似,HTTP響應也由3個部分構成,分別是:
l 協議狀態版本代碼描述
l 響應頭(Response Header)
l 響應正文
下面是一個HTTP響應的例子:
HTTP/1.1 200 OK
Server:Apache Tomcat/5.0.12
Date:Mon,6Oct2003 13:23:42 GMT
Content-Length:112
 
<html>
<head>
<title>HTTP響應示例<title>
</head>
<body>
Hello HTTP!
</body>
</html>
協議狀態代碼描述HTTP響應的第一行類似於HTTP請求的第一行,它表示通信所用的協議是HTTP1.1服務器已經成功的處理了客戶端發出的請求(200表示成功):
HTTP/1.1 200 OK
響應頭(Response Header)響應頭也和請求頭一樣包含許多有用的信息,例如服務器類型、日期時間、內容類型和長度等:
   Server:Apache Tomcat/5.0.12
Date:Mon,6Oct2003 13:13:33 GMT
Content-Type:text/html
Last-Moified:Mon,6 Oct 2003 13:23:42 GMT
Content-Length:112
 響應正文響應正文就是服務器返回的HTML頁面:
  <html>
<head>
<title>HTTP響應示例<title>
</head>
<body>
Hello HTTP!
</body>
</html>
響應頭和正文之間也必須用空行分隔。  
l        HTTP應答碼
   HTTP應答碼也稱爲狀態碼,它反映了Web服務器處理HTTP請求狀態。HTTP應答碼由3位數字構成,其中首位數字定義了應答碼的類型:
   1XX-信息類(Information),表示收到Web瀏覽器請求,正在進一步的處理中
   2XX-成功類(Successful),表示用戶請求被正確接收,理解和處理例如:200 OK
      3XX-重定向類(Redirection),表示請求沒有成功,客戶必須採取進一步的動作。
      4XX-客戶端錯誤(Client Error),表示客戶端提交的請求有錯誤 例如:404 NOT
                                    Found,意味着請求中所引用的文檔不存在。
      5XX-服務器錯誤(Server Error)表示服務器不能完成對請求的處理:如 500
      對於我們Web開發人員來說掌握HTTP應答碼有助於提高Web應用程序調試的效率和準確性。



第3節:參考網站

http://www.iteye.com/topic/154258

http://www.cnblogs.com/yin-jingyu/archive/2011/08/01/2123548.html

http://blog.csdn.net/javaalpha/article/details/6154437

http://lavasoft.blog.51cto.com/62575/175911/

http://blog.csdn.net/jionghan3855/article/details/2247490


第4節:札記



第1章:實例

http請求處理類(HttpClientHandler.java):


package com.mcc.core.net;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Map;
import java.util.Vector;

/**
 * Http請求服務處理類
 *
 * @author <a href="mailto:[email protected]">menergy</a>
 *         DateTime: 14-2-24  下午2:56
 */
public class HttpClientHandler {
    private String defaultContentEncoding;

    public HttpClientHandler() {
        this.defaultContentEncoding = Charset.defaultCharset().name();
    }

    /**
     * 發送GET請求
     *
     * @param urlString
     *            URL地址
     * @return 響應對象
     * @throws IOException
     */
    public HttpRespons sendGet(String urlString) throws IOException {
        return this.send(urlString, "GET", null, null);
    }

    /**
     * 發送GET請求
     *
     * @param urlString
     *            URL地址
     * @param params
     *            參數集合
     * @return 響應對象
     * @throws IOException
     */
    public HttpRespons sendGet(String urlString, Map<String, String> params)throws IOException {
        return this.send(urlString, "GET", params, null);
    }

    /**
     * 發送GET請求
     *
     * @param urlString
     *            URL地址
     * @param params
     *            參數集合
     * @param propertys
     *            請求屬性
     * @return 響應對象
     * @throws IOException
     */
    public HttpRespons sendGet(String urlString, Map<String, String> params,Map<String, String> propertys) throws IOException {
        return this.send(urlString, "GET", params, propertys);
    }

    /**
     * 發送POST請求
     *
     * @param urlString
     *            URL地址
     * @return 響應對象
     * @throws IOException
     */
    public HttpRespons sendPost(String urlString) throws IOException {
        return this.send(urlString, "POST", null, null);
    }

    /**
     * 發送POST請求
     *
     * @param urlString
     *            URL地址
     * @param params
     *            參數集合
     * @return 響應對象
     * @throws IOException
     */
    public HttpRespons sendPost(String urlString, Map<String, String> params)throws IOException {
        return this.send(urlString, "POST", params, null);
    }

    /**
     * 發送POST請求
     *
     * @param urlString
     *            URL地址
     * @param params
     *            參數集合
     * @param propertys
     *            請求屬性
     * @return 響應對象
     * @throws IOException
     */
    public HttpRespons sendPost(String urlString, Map<String, String> params,Map<String, String> propertys) throws IOException {
        return this.send(urlString, "POST", params, propertys);
    }

    /**
     * 發送HTTP請求
     *
     * @param urlString
     * @return 響映對象
     * @throws IOException
     */
    private HttpRespons send(String urlString, String method,Map<String, String> parameters, Map<String, String> propertys)throws IOException {
        HttpURLConnection urlConnection = null;

        if (method.equalsIgnoreCase("GET") && parameters != null) {
            StringBuffer param = new StringBuffer();
            int i = 0;
            for (String key : parameters.keySet()) {
                if (i == 0)
                    param.append("?");
                else
                    param.append("&");
                param.append(key).append("=").append(parameters.get(key));
                i++;
            }
            urlString += param;
        }
        URL url = new URL(urlString);
        urlConnection = (HttpURLConnection) url.openConnection();

        urlConnection.setRequestMethod(method);
        urlConnection.setDoOutput(true);
        urlConnection.setDoInput(true);
        urlConnection.setUseCaches(false);

        if (propertys != null)
            for (String key : propertys.keySet()) {
                urlConnection.addRequestProperty(key, propertys.get(key));
            }

        if (method.equalsIgnoreCase("POST") && parameters != null) {
            StringBuffer param = new StringBuffer();
            for (String key : parameters.keySet()) {
                param.append("&");
                param.append(key).append("=").append(parameters.get(key));
            }
            urlConnection.getOutputStream().write(param.toString().getBytes());
            urlConnection.getOutputStream().flush();
            urlConnection.getOutputStream().close();
        }

        return this.makeContent(urlString, urlConnection);
    }

    /**
     * 得到響應對象
     *
     * @param urlConnection
     * @return 響應對象
     * @throws IOException
     */
    private HttpRespons makeContent(String urlString,HttpURLConnection urlConnection) throws IOException {
        HttpRespons httpResponser = new HttpRespons();
        try {
            InputStream in = urlConnection.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
            httpResponser.contentCollection = new Vector<String>();
            StringBuffer temp = new StringBuffer();
            String line = bufferedReader.readLine();
            while (line != null) {
                httpResponser.contentCollection.add(line);
                temp.append(line).append("\r\n");
                line = bufferedReader.readLine();
            }
            bufferedReader.close();

            String ecod = urlConnection.getContentEncoding();
            if (ecod == null)
                ecod = this.defaultContentEncoding;

            httpResponser.urlString = urlString;

            httpResponser.defaultPort = urlConnection.getURL().getDefaultPort();
            httpResponser.file = urlConnection.getURL().getFile();
            httpResponser.host = urlConnection.getURL().getHost();
            httpResponser.path = urlConnection.getURL().getPath();
            httpResponser.port = urlConnection.getURL().getPort();
            httpResponser.protocol = urlConnection.getURL().getProtocol();
            httpResponser.query = urlConnection.getURL().getQuery();
            httpResponser.ref = urlConnection.getURL().getRef();
            httpResponser.userInfo = urlConnection.getURL().getUserInfo();

            httpResponser.content = new String(temp.toString().getBytes(), ecod);
            httpResponser.contentEncoding = ecod;
            httpResponser.code = urlConnection.getResponseCode();
            httpResponser.message = urlConnection.getResponseMessage();
            httpResponser.contentType = urlConnection.getContentType();
            httpResponser.method = urlConnection.getRequestMethod();
            httpResponser.connectTimeout = urlConnection.getConnectTimeout();
            httpResponser.readTimeout = urlConnection.getReadTimeout();

            return httpResponser;
        } catch (IOException e) {
            throw e;
        } finally {
            if (urlConnection != null)
                urlConnection.disconnect();
        }
    }

    /**
     * 默認的響應字符集
     */
    public String getDefaultContentEncoding() {
        return this.defaultContentEncoding;
    }

    /**
     * 設置默認的響應字符集
     */
    public void setDefaultContentEncoding(String defaultContentEncoding) {
        this.defaultContentEncoding = defaultContentEncoding;
    }

    /**
     * Http請求響應對象
     *
     * @author <a href="mailto:[email protected]">menergy</a>
     *         DateTime: 14-2-24  下午3:01
     */
    public class HttpRespons {
        String urlString;

        int defaultPort;

        String file;

        String host;

        String path;

        int port;

        String protocol;

        String query;

        String ref;

        String userInfo;

        String contentEncoding;

        String content;

        String contentType;

        int code;

        String message;

        String method;

        int connectTimeout;

        int readTimeout;

        Vector<String> contentCollection;

        public String getContent() {
            return content;
        }

        public String getContentType() {
            return contentType;
        }

        public int getCode() {
            return code;
        }

        public String getMessage() {
            return message;
        }

        public Vector<String> getContentCollection() {
            return contentCollection;
        }

        public String getContentEncoding() {
            return contentEncoding;
        }

        public String getMethod() {
            return method;
        }

        public int getConnectTimeout() {
            return connectTimeout;
        }

        public int getReadTimeout() {
            return readTimeout;
        }

        public String getUrlString() {
            return urlString;
        }

        public int getDefaultPort() {
            return defaultPort;
        }

        public String getFile() {
            return file;
        }

        public String getHost() {
            return host;
        }

        public String getPath() {
            return path;
        }

        public int getPort() {
            return port;
        }

        public String getProtocol() {
            return protocol;
        }

        public String getQuery() {
            return query;
        }

        public String getRef() {
            return ref;
        }

        public String getUserInfo() {
            return userInfo;
        }

    }

    public static void main(String args[]){
        try {
            HttpClientHandler httpClientHandler = new HttpClientHandler();
            HttpRespons httpRespons = httpClientHandler.sendGet("http://www.csdn.net");

            System.out.println(httpRespons.getUrlString());
            System.out.println(httpRespons.getProtocol());
            System.out.println(httpRespons.getHost());
            System.out.println(httpRespons.getPort());
            System.out.println(httpRespons.getContentEncoding());
            System.out.println(httpRespons.getMethod());

            System.out.println(httpRespons.getContent());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章