【Java基础】网络编程-URL处理

什么是URL

URL(Uniform Resource Locator)中文名为统一资源定位符,有时也被俗称为网页地址。表示为互联网上的资源,如网页或者FTP地址。

URL语法

protocol://host:port/path?query#fragment

  • protocol(协议)位置处可以是 HTTP、HTTPS、FTP 和 File,port 为端口号,path为文件路径及文件名

解析

  • http://www.baidu.com/index.html?language=cn#j2se
    协议为(protocol):http
    主机为(host:port):www.runoob.com
    端口号为(port): 80 ,以上URL实例并未指定端口,因为 HTTP 协议默认的端口号为 80。
    文件路径为(path):/index.html
    请求参数(query):language=cn
    定位位置(fragment):j2se,定位到网页中 id 属性为 j2se 的 HTML 元素位置 。

URL类

构造方法
  • java.net包中定义了URL类用来处理URL
方法 说明
public URL(String protocol, String host, int port, String file) 通过指定(协议、主机名、端口号、文件名)创建URL 对象
public URL(String protocol, String host, String file) 通过指定(协议、主机名、文件名)创建URL对象,端口使用协议的默认端口
public URL(String url) 通过指定的URL地址创建URL对象
public URL(URL context, String url) 使用基本路径URL对象相对URL地址创建URL对象
常用方法
  • URL类中下有很多用于访问URL的各个部分
方法 说明
public String getPath() 返回URL路径部分
public String getQuery() 返回URL查询部分
public String getAuthority() 获取此 URL 的授权部分
public int getPort() 返回URL端口部分
public int getDefaultPort() 返回协议的默认端口号
public String getProtocol() 返回URL的协议
public String getHost() 返回URL的主机
public String getFile() 返回URL文件名部分
public String getRef() 获取此 URL 的锚点(也称为"引用")
public URLConnection openConnection() 打开一个URL连接,并运行客户端访问资源。
例如:1.如果连接的是HTTP协议的URL, openConnection() 方法返回 HttpURLConnection 对象。
2.如果连接的URL为 JAR 文件, openConnection() 方法将返回 JarURLConnection 对象。
public final InputStream openStream() 获取当前URL请求的响应流

@Test
    public void testUrl() {
        //描述: URL(Uniform Resource Locator)中文名为统一资源定位符,有时也被俗称为网页地址。表示为互联网上的资源,如网页或者FTP地址。
        //语法: protocol://host:port/path?query#fragment
        //protocol(协议)可以是 HTTP、HTTPS、FTP 和 File,port 为端口号,path为文件路径及文件名。

        try {

            URL url = new URL("http://www.baidu.com/index.html?language=cn#j2se");//必须用完整的域名(例,http://www.baidu.com/),不能(例,www.baidu.com/)这样会报错!
            System.out.println("URL 为:" + url.toString());//    http://www.baidu.com/index.html?language=cn#j2se
            System.out.println("协议为:" + url.getProtocol());//   http
            System.out.println("验证信息:" + url.getAuthority());// www.baidu.com
            System.out.println("文件名及请求参数:" + url.getFile());/// index.html?language=cn
            System.out.println("主机名:" + url.getHost());//   www.baidu.com
            System.out.println("路径:" + url.getPath());// /index.html
            System.out.println("端口:" + url.getPort());// -1 因为创建URL实例的时候没有指定端口号
            System.out.println("默认端口:" + url.getDefaultPort());//80
            System.out.println("请求参数:" + url.getQuery());// language=cn
            System.out.println("定位位置:" + url.getRef()); //j2se

            //获取当前URL响应流,并输出
            BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream(), "GBK"));
            while (br.readLine() != null) {
                System.out.println(br.readLine());
            }

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

测试结果
在这里插入图片描述

发起请求
  • 方式1:利用URL类的openStream()方法

    1.构造一个URL对象;
    2.调用这个URL对象的openConnection()获取一个对应该URL的URLConnection对象;
    3.配置这个URLConnection;
    4.读取首部字段;
    5.获得输入流并读取数据;
    6.获得输出流并写入数据;
    7.关闭连接;

    @Test
    public void testURL() {
        InputStream conn = null;//得到字节输入流
        try {
            URL url = new URL("https://blog.csdn.net/qq877728715/article/details/103858729");
            conn = url.openStream();
            BufferedReader bread = new BufferedReader(new InputStreamReader(conn, "UTF-8"));//将字节输入流转换为字符输入流,将字符输入流添加到缓存中
            while (bread.readLine() != null) {
                System.out.println(bread.readLine());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                conn.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    执行结果: 在这里插入图片描述

URLConnection类

  • 通过URL的openConnection() 返回一个URLConnection兑现创建
  • URLConnection 类是一个抽象类,代表应用程序和URL之间的通信连接,此类的实例可用于读取和写入此URL引用的资源。
  • URLConnection 允许使用GET,POST或者其他HTTP方法请求方式将请求数据发送到服务器。
常用方法
方法 说明
long getDate() 返回响应时间
Object getContent() 获取响应内容=>该方法实质上与URL类的getContent()方法相同。使用该方法JVM需要识别和理解该内容类型。该方法只用于支持类似HTTP的协议,协议需要对MIME内容类型有较清楚的了解。若内容未知,或协议无法理解内容类型,getContent()会抛出一个UnknowServiceException异常。
Object getContent(Class[] classes) 获取响应内容并转换成指定对象=>该方法可以选择将内容转换为哪个类对象,以提供数据的不同对象表示。该方法尝试以classes数组中某个类的形式返回内容。优先顺序就是数组的顺序。若任何一种请求类型都不可用,此方法会返回null。
String getContentEncoding() 返回响应头部 content-encoding 字段值
int getContentLength() 返回响应头部 content-length字段值 =>返回响应内容中字节数。如果没有Content-Length首部,getContentLength()就返回-1
long getContentLengthLong() java7新增,返回响应头部 content-length字段值 =>返回响应内容中字节数。如果没有Content-Length首部,getContentLength()就返回-1, 返回类型变为long
String getContentType() 返回响应头部 content-type 字段值 =>返回响应主体的MIME内容类型。如果没有提供内容类型,它不会抛出异常,而是返回null;
int getLastModified() 返回响应头部 last-modified 字段值=>返回响应文档的最后修改日期。
long getExpiration() 返回响应头部 expires 字段值=>有些文档有基于服务器的过期日期,指示应当何时从缓存中删除文档,并从服务器重新下载。如果HTTP首部没有包括Expiration字段,getExpiration()就返回0,这表示文档不会过期,将永远保留在缓存中
long getIfModifiedSince() 返回对象的 ifModifiedSince 字段值。
public void setDoInput(boolean input) URL 连接可用于输入和/或输出。如果打算使用 URL 连接进行输入,则将 DoInput 标志设置为 true;如果不打算使用,则设置为 false。默认值为 true。
public void setDoOutput(boolean output) URL 连接可用于输入和/或输出。如果打算使用 URL 连接进行输出,则将 DoOutput 标志设置为 true;如果不打算使用,则设置为 false。默认值为 false。
public InputStream getInputStream() 返回URL的输入流,用于读取资源
返回URL的输出流, 用于写入资源 返回URL的输出流, 用于写入资源。
public URL getURL() 返回 URLConnection 对象连接的URL
public String getHeaderField(int n) 获取第 n 个头字段的值
public String getHeaderField(String name) 获取指定的头字段的值
public Map getHeaderFields() 返回所有url响应头信息
读取服务器
  • 方式二:使用openConnection()方法创建一个URLConnection类的对象。

    1.构造一个URL对象;
    2.调用这个URL对象的openConnection()方法,获取对应该该URL的URLConnection对象;
    3.调用这个URLConnection的getInputStream()方法;
    4.使用通常的流API读取输入流;
    5.关闭连接

    @Test
    public void testOpenConnection() {
        BufferedReader br = null;
        try {
            URL url = new URL("https://blog.csdn.net/qq877728715/article/details/103305194");
            URLConnection conn=url.openConnection();
             br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));//将字节输入流转换为字符输入流,将字符输入流添加到缓存中
            while (br.readLine() != null) {
                System.out.println(br.readLine());
            }
            
            conn.getInputStream().close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    执行结果:
    在这里插入图片描述
向服务器写入数据
获取首部

获取响应头

String getContentType()
  返回 Content-type 头字段的值。即数据的MIME内容类型。若类型不可用,则返回null。
  除了HTTP协议,极少协议会使用MIME首部。若内容类型是文本。则Content-type首部可能会包含一个标识内容编码方式的字符集。
例:Content-type:text/html; charset=UTF-8

int getContentLength()
  返回 Content-length 头字段的值。该方法获取内容的字节数。许多服务器只有在传输二进制文件才发送Content-length首部,在传输文本文件时并不发送。若没有该首部,则返回-1。
  若需要知道读取的具体字节数,或需要预先知道创建足够大的缓冲区来保存数据时,可以使用该方法。
 
String getContentEncoding()
  返回 Content-encoding 头字段的值。获取内容的编码方式。若内容无编码,则该方法返回null。
  注意:Content-encoding(内容编码)与字符编码不同。字符编码方式由Content-type首部或稳定内容的信息确定,它指出如何使用字节指定字符。内容编码方式则指出字节如何编码其他字节。
例:若编码格式为x-gzip,则可以使用java.util.zip.GZipInputStream来解码。

long getDate()
  返回 date 头字段的值。获取请求的发送时间。即自190011日子夜后过去的毫秒数。
  注意:这是从服务器的角度看到的发送时间。可能与本地时间不一致。若首部不包括Date字段,则返回0long getExpiration()
  返回 expires 头字段的值。获取Expires的值。若无该字段,则返回00即表示不过期,永远缓存。
  注意:该值是自197011日上午12:00后的毫秒数。
 
long getLastModified()
  返回 last-modified 头字段的值。该值是自190011日子夜后过去的毫秒数。若无该字段,则返回0

在这里插入图片描述

获取任意首部字段

String getHeaderField(String name)
	返回指定的头字段的值。

Map<String,List<String>> getHeaderFields()
	返回头字段的不可修改的 Map。

String getHeaderFieldKey(int n)
	返回第 n 个头字段的键。

String getHeaderField(int n)
	返回第 n 个头字段的值。

long getHeaderFieldDate(String name, long Default)
	返回解析为日期的指定字段的值。

int getHeaderFieldInt(String name, int Default)
	返回解析为数字的指定字段的值。
配置首部
  1. 客户端向服务器发送请求,不仅会发送请求行,还发送首部。
  2. 通过在客户端请求和服务器响应首部中放置不同的字段,Web服务器可以根据此信息向不同客户端提供不同的页面,获取和设置cookie,通过口令设置用户等等。
  3. 每个URLConnection的具体子类都在首部中设置一些默认的键值对(实际上只有HttpURLConnection这样做,因为HTTP是唯一以这种方式使用首部的主要协议。
  4. 只能在连接打开之前使用。如果连接已经打开,它将抛出一个IllegalArgumentException异常;
//设置请求属性值
void setRequestProperty(String key, String value)
	此方法只在连接打开之前打开,将会抛出IllegalStateException异常。但该方法仅支持对一个首部设置一个值。


//使用如下方法为首部增加值:
//HTTP允许一个属性有多个值。各个值之间用逗号隔开。
//例:cookie:username=sjq; session=hdfu23asdjf901j;
该方法用于添加某个指定首部字段的值。
	void addRequestProperty(String key, String value)
 
//获取请求属性值 
根据请求属性名获取指定首部字段:
	String getRequestProperty(String key)

以获得连接的所有请求属性并作为一个Map返回
	Map<String,List<String>> getRequestProperties()
//以上方法用于获取URLConneciton所拥有HTTP首部。 
配置连接

URLConnection类的protected成员变量如下:

protected  URL url
	该字段指定URLConnection连接的URL。构造函数会在创建URLConnection时设置,此后就不能再改变。

protected  boolean connected
	当连接打开时,该字段为true。若连接关闭,则为false。没有直接读取或改变connected值的方法。任何导致URLConnection连接的方法都会将此变量设为true,包括connect()getInputStream(),和getOutputStream()。

	任何导致URLConnection断开的方法都会将此字段设为false。

	java.net.URLConnection没有断开方法,但一些子类,如java.net.HttpURLConnection
中存在这样的方法。

protected  boolean allowUserInteraction
	该字段表示是否允许与用户交互。默认为false,即不允许交互。该值只能在URLConnection连接前设置。
	例:Web浏览器可能需要访问用户名和口令。

protected  boolean doInput
	该字段在URLConnection可用于输入时为true,否则为false。默认为trueprotected  boolean doOutput
	该字段在URLConnection可用于输出时为true,否则为false。默认为falseprotected  long ifModifiedSince
	该字段指示了将放置If-Modified-Since首部字段中的日期(格林威治标准时间197011日子夜后的毫秒数)。

protected  boolean useCaches
	该字段指定了是否可以在缓存可用时使用缓存。默认为true,表示缓存将被使用;false表示缓存不被使用。
  • 以上字段定义了客户端如何向服务器作出请求。这些字段只能在URLConnection连接前修改。否则抛出IllegalStateException异常。

每个字段都有一些相应的方法。
URL getURL()
void setDoInput(boolean doinput)
boolean getDoInput()
void setDoOutput(boolean dooutput)
boolean getDoOutput()
void setUseCaches(boolean usecaches)
boolean getUseCaches()
void setAllowUserInteraction(boolean allowuserinteraction)
boolean getAllowUserInteraction()
void setIfModifiedSince(long ifmodifiedsince)
long getIfModifiedSince()

还有一些方法,这些方法用于定义和获取URLConnection对象的默认行为:
static boolean getDefaultAllowUserInteraction()
boolean getDefaultUseCaches()
void setDefaultUseCaches(boolean defaultusecaches)
static void setDefaultAllowUserInteraction(boolean defaultallowuserinteraction)
static void setFileNameMap(FileNameMap map)
static FileNameMap getFileNameMap()

设置响应超时时间

Java1.5新增4个方法用来获取和修改连接的超时值。也就是说,底层socket等待远程服务器的响应时,等待多长时间后会抛出SocketTimeoutException异常

设置获取读取的超时值,单位为毫秒。(控制socket等待建立连接的时间)
	int getReadTimeout()
	void setReadTimeout(int timeout)

设置获取连接的超时值,单位为毫秒。(控制输入流等待数据到达的时间)
	int getConnectTimeout()
	void setConnectTimeout(int timeout)
  • 这四个方法设置0表示为永不超时。如果超时值为负数。两个设置方法都会抛出IllegalArgumentException异常
使用URLConnection与服务器交互
InputStream getInputStream()
	返回从此打开的连接读取的输入流。

OutputStream getOutputStream()
	返回写入到此连接的输出流。
  1. 若只是向服务器请求数据,则为HTTP请求方法为GET。

  2. 若需要向服务器提交数据,必须在先调用setDoOutput(true)当doOutput属性为true时,请求方法将由GET变为POST。

获取内容
Object getContent()
	该方法实质上与URL类的getContent()方法相同。使用该方法JVM需要识别和理解该内容类型。
	该方法只用于支持类似HTTP的协议,协议需要对MIME内容类型有较清楚的了解。
	若内容未知,或协议无法理解内容类型,getContent()会抛出一个UnknowServiceException异常。

Object getContent(Class[] classes)
	该方法可以选择将内容转换为哪个类对象,以提供数据的不同对象表示。
	该方法尝试以classes数组中某个类的形式返回内容。优先顺序就是数组的顺序。
	若任何一种请求类型都不可用,此方法会返回null。
URLConnection的安全

建立网络连接、读写文件等等存在一些安全限制,URLConnection对象会受到这些安全限制的约束。

Permission getPermission()
	该方法返回Permission对象,指出连接此URL所需的许可权。
	如果没有所需的许可权(即没有适当的安全管理器),它就会返回null。 
ContentHandlerFactory
URLConnection类包括一个静态的ContentHandler。即内容处理器。通过以下方法设置内容处理器工厂。
static void setContentHandlerFactory(ContentHandlerFactory fac)
HttpURLConnection
  1. java.net.HttpURLConnection类是URLConnection的抽象子类,它提供了一些有助于专门操作http请求的额外方法。

  2. sun.net.www.protocol.http包中也提供了一个HttpURLConnection类。该类实现了抽象的connect()方法。但一般很少直接访问该类。

URL实例的openConnection()会根据连接的不同,返回不同的Connection对象

  • 如果你连接HTTP协议的URL, openConnection() 方法返回 HttpURLConnection 对象。
  • 如果你连接的URL为一个 JAR 文件, openConnection() 方法将返回 JarURLConnection 对象。
@Test
    public void testURLConnection() {
        BufferedReader in = null;
        try {
            URL url = new URL("https://blog.csdn.net/qq877728715/article/details/103858729");
            URLConnection urlConnection = url.openConnection();
            HttpURLConnection connection = null;
            if (urlConnection instanceof HttpURLConnection) {
                connection = (HttpURLConnection) urlConnection;
            } else {
                System.out.println("请输入 URL 地址");
                return;
            }
            in = new BufferedReader(new InputStreamReader(connection.getInputStream()));

            String content = null;
            while ((content = in.readLine()) != null) {
                System.out.println(content);
            }

            connection.getInputStream().close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
猜测MIME内容类型
static String guessContentTypeFromName(String fname)
	根据 URL 的指定 "file" 部分尝试确定对象的内容类型。

static String guessContentTypeFromStream(InputStream is)
	根据输入流的开始字符尝试确定输入流的类型。
设置获取请求类型

HTTP协议提供了7中请求方法:

  • GET
  • POST
  • HEAD
  • PUT
  • OPTIONS
  • DELETE
  • TRACE

通过以下方法设置请求方法:

若请求类型不是上面7个方法的字符串,则会抛出java.net.ProtocolException异常。
一般只设置请求方法是不够的,还需要调整HTTP首部,还要提供消息体。
	void setRequestMethod(String method)


获取HTTP请求方法
	String getRequestMethod()
断开与服务器的连接
  1. HTTP1.1支持持久连接,允许通过一个TCP socket发送多个请求和响应。

  2. HTTPKeep-AliveWeb连接的性能有所提升允许多个请求和响应通过一个TCP连接连续发送。

  3. 客户端通过HTTP请求首部包含Connection字段及Keep-Alive表示客户端愿意使用Keep-Alive:

    Connection: Keep-Alive
    
  4. 当使用Keep-Alive时,服务器不再因为向客户端发送最后一个字节数据就关闭连接。毕竟客户端还可能发送另一个请求。因此客户端需要负责关闭连接。

    Java提供如下方法关闭连接,实际上很少使用该方法:
    abstract  void disconnect()
    //如果这个连接上还有打开的流,disconnect()将关闭这些流。
    //不过,反过来并不成立。关闭一个持久连接上的流时,并不会关闭这个socket并断开连接;
    
获取错误响应
  • 如果HTTP响应状态为4xx(客户端错误)或者5xx(服务器错误),你可以通过HttpUrlConnection.getErrorStream()来查看服务器发送过来的信息。
	InputStream getErrorStream()
	//例:InputStream error = ((HttpURLConnection) connection).getErrorStream();
  • 如果HTTP响应状态为-1,就是出现了连接错误。 HttpURLConnection会保持连接一直可用,如果你想关闭这个特性,需要把http.keepAlive设置为false:
    System.setProperty("http.keepAlive", "false");
    
Http响应码
  • HTTP响应的第一行被称为消息响应。该信息不会被URLConnection的getHeaderFiled()方法读取
    String getResponseMessage()
    	返回消息响应。如:HTTP/1.1 404 Not Found
    
    int getResponseCode()
    	返回消息响应码。如:404

HttpURLConnection类提供了常见响应码常量。具体请参考JDK文档。

重定向
  1. 默认情况下,HttpURLConnection类会跟踪重定向。但HttpURLConnection有两个静态方法,可以确定是否跟随重定向。

    static void setFollowRedirects(boolean set)
    static boolean getFollowRedirects()
    	若跟随,则为true,否则为false

    这两个是静态方法,它们会改变该方法后构造的所有HttpURLConnection对象的行为。若安全管理器不允许其改变,则会抛出SecurityException异常。

  2. 也可以对某个HttpURLConnection实例设置是否重定向。

    void setInstanceFollowRedirects(boolean followRedirects)
    boolean getInstanceFollowRedirects()
    
代理
  • HttpURLConnection可以得知请求是否通过了代理服务器。
    abstract  boolean usingProxy()
    
流模式
  1. 每个发送给HTTP服务器的请求都有HTTP首部。首部中有一个Content-type字段;即请求体中的字节数。首部位于主体的前面。为了写入首部,需要知道主体的长度,而在写首部的时候可能还不知道主题的长度。

  2. 一般情况下Java的解决办法是,对于从HttpURLConnection获取的OutputStream,缓存写入到此OutputStream中的所有内容,直到流被关闭。到这时,它就知道了主体中有多少字节,

  3. 在请求发送之前,HttpURLConnetion会把所有需要发送的数据放到缓冲区里,不管你是否使用connection.setRequestProperty("Content-Length", contentLength);设置了contentLength,当你并行发送大量的POST请求时,这可能会引起OutOfMemoryExceptions异常,为了避免这个问题,需要使用如下方法:

    void setFixedLengthStreamingMode(int contentLength)
    此方法用于在预先已知内容长度时启用没有进行内部缓冲的 HTTP 请求正文的流。
    
    //例:httpConnection.setFixedLengthStreamingMode(contentLength);
    
  4. 但是如果不能事先知道内容的长度,可以使用HttpURLConnection.setChunkedStreamingMode()方法设置为块状流模式。块状流模式的情况下,放在块里的内容将会被强行发送出去。下边的例子将会把发送的内容按照每块1KB的大小发送出去。

    void setChunkedStreamingMode(int chunklen)
      此方法用于在预先不知道内容长度时启用没有进行内部缓冲的 HTTP 请求正文的流。
    
    //例:httpConnection.setChunkedStreamingMode(1024);
    
URL和URLConnection区别
  • URLConnection提供了对HTTP请求头(首部)的访问;
  • URLConnection可以配置发送给服务器的请求参数;
  • URLConnection除了读取服务器数据外,还可以向服务器写入数据;

注意: URL必须用完整的域名(http://www.baidu.com/),不能(www.baidu.com/)这样会报错!

使用HttpURLConnection进去get/post请求

在进行参数传递时,如果出现有中文参数,需要对参数进行编码处理,即 URLEncoder.encode( param,"UTF-8")

public class HttpClientUtil {
 /**
     * 向指定URL发送GET方法的请求
     *
     * @param requestUrl 发送请求的URL
     * @param param      请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return URL所代表远程资源的响应结果
     */
    public String get(String requestUrl, String param) {

        HttpURLConnection connection = null;
        InputStream is = null;
        BufferedReader br = null;
        String result = null;

        try {
            /** 创建远程url连接对象 */
            URL url = new URL(requestUrl + "?" + param);

            /** 通过远程url对象打开一个连接,强制转换为HttpUrlConnection类型 */
            connection = (HttpURLConnection) url.openConnection();

            /** 设置连接方式:GET */
            connection.setRequestMethod("GET");
            /** 设置连接主机服务器超时时间:15000毫秒 */
            connection.setConnectTimeout(15000);
            /** 设置读取远程返回的数据时间:60000毫秒 */
            connection.setReadTimeout(60000);

            /** 设置通用的请求属性 */
            connection.setRequestProperty("accept", "*/*");//此处为暴力方法设置接受所有类型,以此来防范返回415;
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 设置传入参数的格式:请求参数应该是 name1=value1&name2=value2 的形式
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

            /** 发送GET方式请求,使用connet方法建立和远程资源之间的实际连接即可 */
            connection.connect();

            /*-------------------------->*/
            /** 获取所有相应头字段 */
            Map<String, List<String>> map = connection.getHeaderFields();
            /** 遍历响应头字段 */
            for (String key : map.keySet()) {
                System.out.println(key + "---------->" + map.get(key));
            }
            /* <-------------------------- */

            /** 请求成功:返回码为200 */
            if (connection.getResponseCode() == 200) {
                /** 通过connection连接,获取输入流 */
                is = connection.getInputStream();
                /** 封装输入流is,并指定字符集 */
                br = new BufferedReader(new InputStreamReader(is, "UTF-8"));

                /** 存放数据 */
                StringBuffer sbf = new StringBuffer();
                String line = null;
                while ((line = br.readLine()) != null) {
                    sbf.append(line);
                    sbf.append("\r\n");
                }
                result = sbf.toString();
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            /** 关闭资源 */
            try {
                if (null != br) {
                    br.close();
                }
                if (null != is) {
                    is.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            /** 关闭远程连接 */
            // 断开连接,最好写上,disconnect是在底层tcp socket链接空闲时才切断。如果正在被其他线程使用就不切断。
            // 固定多线程的话,如果不disconnect,链接会增多,直到收发不出信息。写上disconnect后正常一些
            connection.disconnect();
            System.out.println("--------->>> GET request end <<<----------");
        }
        return result;
    }
    /**
     * 向指定 URL 发送POST方法的请求
     *
     * @param requestUrl 发送请求的 URL
     * @param param      请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return 所代表远程资源的响应结果
     */
    public String post(String requestUrl, String param) {
        HttpURLConnection connection = null;
        InputStream is = null;
        OutputStream os = null;
        BufferedReader br = null;
        String result = null;

        try {
            /** 创建远程url连接对象 */
            URL url = new URL(requestUrl);

            /** 通过远程url对象打开一个连接,强制转换为HttpUrlConnection类型 */
            connection = (HttpURLConnection) url.openConnection();

            /** 设置连接方式:POST */
            connection.setRequestMethod("POST");
            /** 设置连接主机服务器超时时间:15000毫秒 */
            connection.setConnectTimeout(15000);
            /** 设置读取远程返回的数据时间:60000毫秒 */
            connection.setReadTimeout(60000);

            /** 设置是否向httpUrlConnection输出,设置是否从httpUrlConnection读入,此外发送post请求必须设置这两个 */
            // 默认值为:false,当向远程服务器传送数据/写数据时,需要设置为true
            connection.setDoOutput(true);
            // 默认值为:true,当前向远程服务读取数据时,设置为true,该参数可有可无
            connection.setDoInput(true);

            /** 设置通用的请求属性 */
            connection.setRequestProperty("accept", "*/*");//此处为暴力方法设置接受所有类型,以此来防范返回415;
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
             
             /** 设置传入参数的格式为json*/
			/**connection.setRequestProperty("Content-Type","application/json; charset=UTF-8");*/
            // 设置传入参数的格式:请求参数应该是 name1=value1&name2=value2 的形式
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
          


            /** 通过连接对象获取一个输出流 */
            os = connection.getOutputStream();
            /** 通过输出流对象将参数写出去/传输出去,它是通过字节数组写出的 */
            // 若使用os.print(param);则需要释放缓存:os.flush();即使用字符流输出需要释放缓存,字节流则不需要
            if (param != null && param.length() > 0) {
                os.write(param.getBytes());
            }
            os.flush();
            /** 请求成功:返回码为200 */
            if (connection.getResponseCode() == 200) {
            /** 通过连接对象获取一个输入流,向远程读取 */
                is = connection.getInputStream();
            /** 封装输入流is,并指定字符集 */
                br = new BufferedReader(new InputStreamReader(is, "UTF-8"));

            /** 存放数据 */
                StringBuffer sbf = new StringBuffer();
                String line = null;
                while ((line = br.readLine()) != null) {
                    sbf.append(line);
                    sbf.append("\r\n");
                }
                result = sbf.toString();
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            /** 关闭资源 */
            try {
                if (null != br) {
                    br.close();}
                if (null != is) {is.close();
                }
                if (null != os) {os.close();}
            } catch (Exception e) {
                e.printStackTrace();
            }
            /** 关闭远程连接 */
            // 断开连接,最好写上,disconnect是在底层tcp socket链接空闲时才切断。如果正在被其他线程使用就不切断。
            // 固定多线程的话,如果不disconnect,链接会增多,直到收发不出信息。写上disconnect后正常一些
            connection.disconnect();
            System.out.println("--------->>> POST request end <<<----------");
        }
        return result;
    }
}

关于使用HttpUrlConnection的一些经验总结

发布了62 篇原创文章 · 获赞 109 · 访问量 5275

猜你喜欢

转载自blog.csdn.net/qq877728715/article/details/104032500