HTTP協議:(1)HTTP請求和相關API

一、HTTP請求的知識

TCP/IP協議,關注的是客戶端與服務器端之間數據是否傳輸成功!html

HTTP協議,是在TCP/IP協議之上封裝的一層協議,關注的是數據傳輸的格式是否規範。java

1.一、HTTP請求的示例

HTTP請求由四部分組成:請求行、請求頭、一個空行和實體內容(可選)。web

HTTP請求的組成:瀏覽器

|--請求行緩存

|--請求頭tomcat

|--(一個空行)服務器

|--實體內容(只有POST請求時纔有)cookie


HTTP請求的一個示例:app

GET /myweb/hello HTTP/1.1               --請求行
Host: localhost:8080                    --請求頭(多個key-value對象)
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,en-us;q=0.8,zh;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
                                        -- 一個空行
name=rk&password=123456               --(可選)實體內容


1.二、請求行

GET /myweb/hello HTTP/1.1               --請求行

#http協議版本less

http1.0:當前瀏覽器客戶端與服務器端創建鏈接以後,只能發送一次請求,一次請求以後鏈接關閉。

http1.1:當前瀏覽器客戶端與服務器端創建鏈接以後,能夠在一次鏈接中發送屢次請求。(如今基本上都使用1.1)

#請求資源

URL:  統一資源定位符。http://localhost:8080/myweb/hello.html。只能定位互聯網資源。是URI的子集。

URI: 統一資源標記符。/myweb/hello。用於標記任何資源。能夠是本地文件系統,局域網的資源(//192.168.14.10/myweb/index.html),能夠是互聯網資源。

#請求方式

常見的請求方式: GET 、 POST、 HEAD、 TRACE、 PUT、 CONNECT 、DELETE

經常使用的請求方式: GET  和 POST

表單提交:

<form action="提交地址" method="GET/POST">

</form>

GET   vs  POST 區別
GET方式 POST方式

a)地址欄(URI)會跟上參數數據。以?開頭,多個參數之間以&分割。

b)GET提交參數數據有限制,不超過1KB。

c)GET方式不適合提交敏感密碼。

d)注意: 瀏覽器直接訪問的請求,默認提交方式是GET方式

a)參數不會跟着URI後面。參數而是跟在請求的實體內容中。

b)POST提交的參數數據沒有限制。

c)POST方式提交敏感數據。

1.三、請求頭

    Accept: text/html,p_w_picpath/*      -- 瀏覽器接受的數據類型
    Accept-Charset: ISO-8859-1     -- 瀏覽器接受的編碼格式
    Accept-Encoding: gzip,compress  --瀏覽器接受的數據壓縮格式
    Accept-Language: en-us,zh-       --瀏覽器接受的語言
    Host: www.it315.org:80          --(必須的)當前請求訪問的目標地址(主機:端口)
    If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT  --瀏覽器最後的緩存時間
    Referer: http://www.it315.org/index.jsp      -- 當前請求來自於哪裏
    User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)  --瀏覽器類型
    Cookie:name=rk                          -- 瀏覽器保存的cookie信息
    Connection: close/Keep-Alive            -- 瀏覽器跟服務器鏈接狀態。close: 鏈接關閉  keep-alive:保存鏈接。
    Date: Tue, 11 Jul 2000 18:23:51 GMT      -- 請求發出的時間


1.四、實體內容

只有POST提交的參數會放到實體內容中


二、HttpServletRequest對象

HttpServletRequest對象做用是用於獲取請求數據。

2.一、HttpServletRequest對象核心API

HttpServletRequest對象核心API
類別 API
請求行

request.getMethod();   請求方式

request.getRequetURI()   / request.getRequetURL()   請求資源

request.getProtocol()   請求http協議版本

請求頭

request.getHeader("名稱")   根據請求頭獲取請求值

request.getHeaderNames()    獲取全部的請求頭名稱

實體內容

request.getInputStream()   獲取實體內容數據

2.二、service和doXXX之間的關係

Servlet繼承關係以下:

|-javax.servlet.Servlet接口

|-javax.servlet.GenericServlet抽象類

|-javax.servlet.http.HttpServlet抽象類


在javax.servlet.Servlet接口中有一個service方法,以下:

public void service(ServletRequest req, ServletResponse res)

在javax.servlet.http.HttpServlet類當中除了覆寫public的service方法以外,還定義了本身的protected的service方法。

public void service(ServletRequest req, ServletResponse res)實現以下:

//Dispatches client requests to the protected service method.
//There's no need to override this method.
public void service(ServletRequest req, ServletResponse res)
    throws ServletException, IOException {

    HttpServletRequest  request;
    HttpServletResponse response;

    try {
        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;
    } catch (ClassCastException e) {
        throw new ServletException("non-HTTP request or response");
    }
    service(request, response);
}

protected void service(HttpServletRequest req, HttpServletResponse resp)實現以下:

//Receives standard HTTP requests from the public service method and
// dispatches them to the doXXX methods defined in this class.
//This method is an HTTP-specific version of the javax.servlet.Servlet.service method.
//There's no need to override this method.
protected void service(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {

    String method = req.getMethod();

    if (method.equals(METHOD_GET)) {
        long lastModified = getLastModified(req);
        if (lastModified == -1) {
            // servlet doesn't support if-modified-since, no reason
            // to go through further expensive logic
            doGet(req, resp);
        } else {
            long ifModifiedSince;
            try {
                ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
            } catch (IllegalArgumentException iae) {
                // Invalid date header - proceed as if none was set
                ifModifiedSince = -1;
            }
            if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                // If the servlet mod time is later, call doGet()
                // Round down to the nearest second for a proper compare
                // A ifModifiedSince of -1 will always be less
                maybeSetLastModified(resp, lastModified);
                doGet(req, resp);
            } else {
                resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            }
        }

    } else if (method.equals(METHOD_HEAD)) {
        long lastModified = getLastModified(req);
        maybeSetLastModified(resp, lastModified);
        doHead(req, resp);

    } else if (method.equals(METHOD_POST)) {
        doPost(req, resp);

    } else if (method.equals(METHOD_PUT)) {
        doPut(req, resp);

    } else if (method.equals(METHOD_DELETE)) {
        doDelete(req, resp);

    } else if (method.equals(METHOD_OPTIONS)) {
        doOptions(req,resp);

    } else if (method.equals(METHOD_TRACE)) {
        doTrace(req,resp);

    } else {
        //
        // Note that this means NO servlet supports whatever
        // method was requested, anywhere on this server.
        //

        String errMsg = lStrings.getString("http.method_not_implemented");
        Object[] errArgs = new Object[1];
        errArgs[0] = method;
        errMsg = MessageFormat.format(errMsg, errArgs);

        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
    }
}


tomcat服務器首先會調用servlet的service方法,而後在service方法中再根據請求方式來分別調用對應的doXX方法。




2.三、傳遞的請求參數如何獲取

在瀏覽器發送HTTP協議的時候,GET方式是將參數放在URI的後面,POST方式是將參數放在實體內容中。

獲取請求參數的API

獲取GET方式參數:request.getQueryString();

獲取POST方式參數:request.getInputStream();

問題:可是以上兩種不通用,並且獲取到的參數還須要進一步地解析。因此可使用統一方便的獲取參數的方式:


request.getParameter("參數名");  根據參數名獲取參數值(注意,只能獲取一個值的參數)

request.getParameterValue("參數名「);根據參數名獲取參數值(能夠獲取多個值的參數)

request.getParameterNames();   獲取全部參數名稱列表


2.四、請求參數編碼問題

修改POST方式參數編碼(這種方式只對POST請求的實體內容有效):

request.setCharacterEncoding("utf-8");

修改GET方式參數編碼:

手動解碼:String name = new String(name.getBytes("iso-8859-1"),"utf-8");