zoukankan      html  css  js  c++  java
  • 廖雪峰Java13网络编程-3其他-1HTTP编程

    1.HTTP协议:

    • Hyper Text Transfer Protocol:超文本传输协议
    • 基于TCP协议之上的请求/响应协议
    • 目前使用最广泛的高级协议
      * 使用浏览器浏览网页和服务器交互使用的就是HTTP协议
      * 手机应用上绝大多数程序与服务器之间交互数据使用的也是HTTP协议。
    • HTTP协议是一个纯文本协议
    • HTTP是一个请求/响应协议。浏览器发送一个请求,服务器收到以后,然后发送响应。

    HTTP 1.0:

    • 每次请求都会创建一个新的HTTP连接,浏览器在请求一个网页之后,往往还是多次请求图片、CSS、JS等其他资源,而创建TCP连接需要一定的时间,所以HTTP1.0传输效率比较低

    HTTP 1.1:
    在HTTP1.0之上做了改进,多个HTTP请求可以通过一个TCP连接来完成。这样浏览器只需要和服务器建立一次TCP连接,就可以反复进行HTTP的请求/响应。它的效率比HTTP1.0要高

    HTTP 2.0:
    又对HTTP多了改进。多个HTTP请求也是通过一次TCP连接来完成的,但是浏览器在发送了一次HTTP请求以后,不需要等待响应,就可以立即发送第2个、第3个,而服务器在接收到请求的同时,又把前面已经接收的请求对应的响应发送出去,也就是说HTTP 2.0 请求/响应是可以异步发送的

    2.HTTP请求格式

    GET POST
    请求 GET / HTTP/1.1 GET方法 路径 HTTP协议版本
    Host: www.baidu.com 请求地址
    User-Agent: Mozilla/5.0 (Linux; Android 9; ALP-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.89 Mobile Safari/537.36
    User-Agent表示浏览器本身,如火狐
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
    Accept表示能接收什么样的数据
    Accept-Language: zh-CN,zh;q=0.9 表示用户的语言
    POST: /dataPipeline/uploadData?channel=statistics&version=v1 HTTP/1.1 请求方法 路径 HTTP协议类型
    Host: cgicol.amap.com
    User-Agent: Dalvik/2.1.0 (Linux; U; Android 9; ALP-AL00 Build/HUAWEIALP-AL00)
    Accept: */*
    Accept-Language: zh-CN,zh,en
    Content-Type: application/x-www-form-urlencoded 数据格式html表单
    Content-Length: 264 数据长度264

    channel=statistics&version=v1... Body具体的数据
    响应 GET响应:HTTP/1.1 302 Found HTTP协议 响应
    Content-Type:text/html;charset=utf-8 响应的内容是网页,编码是utf-8
    Content-Length:0 响应的长度

    响应体和header以空行分隔
    HTTP/1.1 200
    Content-Type: text/html;charset=ISO-8859-1 指定具体类型
    Content-Length: 32086 大小

    响应体

    HTTP请求分为Header和Body2个部分,Header是必须的。Get请求只有Header没有Body,而Post请求既有Header,又有Body。Header和Body之间用一个空行分隔。
    如果浏览器发送的是POST请求,那么浏览器还需要告诉服务器发送的数据格式Content-Type和数据的大小Content-Length,如application/x-www-form-urlencoded表示一个html表单,大小为264个字节。

    HTTP响应也分为Header和Body2个部分,Header是必须的,第1行指出HTTP响应码。2XX正确返回,3XX重定向,4XX客户端错误,5XX服务器错误。
    Header还可以包含各种属性,例如Content-Type指出Body的类型,Content-Length指出Body大小。
    响应体通过一个空行与Header分隔,响应的数据可以是任意的文本或者二进制格式作为body。

    HTTP Server

    • 处理HTTP请求,发送HTTP响应
    • 服务器是通过Java EE Servlet API来定义的

    HTTP Client

    • 发送HTTP请求,接收HTTP响应
    • java.net.HttpURLConnection处理http的客户端

    GET请求示例:

        URL url = new URL("http://www.exampe.com"); //获取URL对象
        HttpURLConnection conn = (HttpURLConnection) url.openConnection(); //通过url对象的openConnection()获取HttpURLConnection对象
        int code = conn.getResponseCode(); //获取响应码
        try(InputStream input = conn.getInputSteam()){ //读取响应数据
            //读取响应数据
        }
        conn.disconnect(); //断开连接
    

    POST请求示例:

        URL url = new URL("http://www.example.com/login");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST"); //默认方法是get
        conn.setDoOutput(true); //需要发送请求的数据
        //指定数据的Content-Type和Content-Length
        byte[] postData = "loginName=test&password=123456".getBytes("UTF-8");
        conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); 
        conn.setRequestProperty("Content-Length",String.valueOf(postData.length));
        try(OutputStream output = conn.getOutputStream()){ //写入请求的数据
            output.write(postData);
        }
        int code = conn.getResponseCode();
        try(inputStream input = conn.getInputStream()){
            //读取响应数据
        }
        conn.disconnect();
    

    示例

    package com.csj2018;
    
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.net.URLEncoder;
    import java.nio.charset.StandardCharsets;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    class Response{
        final int code;
        final byte[] data;
        public Response(int code,byte[] data){
            this.code = code;
            this.data = data;
        }
        @Override
        public String toString(){
            StringBuilder sb = new StringBuilder(1024);
            sb.append("HTTP状态码").append(code).append("
    ");
            String s = new String(data,StandardCharsets.UTF_8);
            if(s.length() > 100){
                sb.append(s.substring(0,100)).append("
    ...");
            }else{
                sb.append(s);
            }
            return sb.toString(); //返回状态码和前100个字节的内容,多于100,以...代表剩余内容
        }
    }
    public class HttpClient {
        public static void main(String[] args) throws Exception{
            Response resp = get("http://www.douban.com");
            System.out.println(resp);
            Map<String,String> postMap = new HashMap<>();
            postMap.put("form_email","test");
            postMap.put("form_password","password");
            Response postResp = post("https://www.douban.com/accounts/login","application/x-www-form-urlencoded",toFormData(postMap));
            System.out.println(postResp);
        }
        static Response get(String theUrl){
            System.err.println("GET:"+theUrl);
            HttpURLConnection conn = null;
            try{
                URL url = new URL(theUrl); //获取URL对象
                conn = (HttpURLConnection) url.openConnection(); //建立连接
                ByteArrayOutputStream responseBuffer = new ByteArrayOutputStream(); //获取一个ByteArrayOutputStream对象用于存放读取的内容
                try(InputStream input = conn.getInputStream()){//获取连接获取的内容
                    byte[] buffer = new byte[1024];
                    for(;;){
                        int n = input.read(buffer);
                        System.err.println("每次读取的大小:"+n);
                        if(n== (-1)){
                            break;
                        }
                        responseBuffer.write(buffer,0,n);//将内容写入到responseBuffer
                        System.out.println("每次写入后responseBuffer的大小"+responseBuffer.size());
                    }
                }
                return new Response(conn.getResponseCode(),responseBuffer.toByteArray());//返回Response对象
            }catch (IOException e){
                throw new RuntimeException(e);
            }finally {
                if(conn != null){
                    conn.disconnect();
                }
            }
        }
        static Response post(String theUrl,String contentType,String contentData){
            System.err.println("POST:"+theUrl);
            HttpURLConnection conn = null;
            try{
                URL url = new URL(theUrl);
                conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("POST"); //请求方法默认get,因此设为post
                conn.setDoOutput(true);
                //添加请求属性,Content-Type, Content-Length
                conn.setRequestProperty("Content-Type",contentType);
                conn.setRequestProperty("Content_Length",String.valueOf(contentData.length()));
                //设置body
                byte[] postData = contentData.getBytes(StandardCharsets.UTF_8); //
                try(OutputStream output = conn.getOutputStream()){
                    output.write(postData);
                }
                ByteArrayOutputStream responseBuffer = new ByteArrayOutputStream();
                try(InputStream input = conn.getInputStream()){
                    byte[] buffer = new byte[1024];
                    for(;;){
                        int n = input.read(buffer);
                        if(n==(-1)){
                            break;
                        }
                        responseBuffer.write(buffer,0,n);
                    }
                }
                return new Response(conn.getResponseCode(),responseBuffer.toByteArray());
            }catch (IOException e){
                throw new RuntimeException(e);
            }finally {
                if(conn != null){
                    conn.disconnect();
                }
            }
        }
        static String toFormData(Map<String,String> map) throws IOException{
            List<String> list = new ArrayList<>(map.size());
            for(String key:map.keySet()){
                list.add(key + "=" + URLEncoder.encode(map.get(key),"UTF-8"));
            }
            return String.join("&",list); //key不编码,value编码,多个参数以&连接
        }
    }
    

    3.总结:

    • HTTP协议是一个基于TCP的请求/响应协议
    • 广泛用于浏览器、手机app与服务器的数据交互
    • Java提供了HttpURLConnection实现HTTP客户端
  • 相关阅读:
    Android APK瘦身方法小结
    快速了解Android重要机制
    Android 画笔Paint
    android 图片凸出
    金钱转换
    WPF属性与特性的映射(TypeConverter)
    XMAL 中x名称控件的Auttribute
    AtCoder Grand Contest 012 B
    scau 17967 大师姐唱K的固有结界
    Centos7开机自动启动服务和联网
  • 原文地址:https://www.cnblogs.com/csj2018/p/11345227.html
Copyright © 2011-2022 走看看