URLConnection(四)

1. 配置客户端请求HTTP首部

HTTP客户端(如浏览器)向服务器发送一个请求行和一个首部,如下:
在这里插入图片描述
web服务器可以根据这个信息向不同的客户端提供不同的页面,获取和设置cookie,通过口令认证用户。通过在客户端发送和服务器响应的首部中放置不同的字段,就可以完成这些工作。在打开连接前可以使用setRequestProoerty()方法为HTTP首部增加首部字段。

public void setRequestProperty(String name,String value)

该方法用指定的名和值为这个URLConnection的首部增加一个字段。这个方法只能在连接打开之前调用。如果连接打开了,它将抛出一个IllegalStateException异常。getRequestProperty()会返回这个URLConnection所用HTTP首部中指定字段的值,public Map<String,List<String>> getRequestProperties()会将字段值用map的形式返回。如果我们要给URLConnection添加新的属性值就调用addRequestProperty(String name, String value)方法。其实并没有一个固定的首部,服务器一般会忽略无法识别的首部,HTTP确实对首部字段的名和值的内容有一定的限制,例如,名不能包含空格,值不能包含换行符号等待,不然getRequestProperty()public Map<String,List<String>> getRequestProperties()会抛出IllegalArgumentException

2. 向服务器写入数据

有时你需要向URLConnection写入数据,例如POST向Web服务器提交表单,获者使用PUT上传文件等。getOutputStream()方法返回一个OutputStream,可以用来吸入数据传送给服务器。

注意由于URLConnection默认情况下不允许输出,所以要调用setDoOutput(true)来运行输出,一旦设置该方法,那么GET方法就会变成POST方法

一旦得到OutputStream就可以串链到BufferdOutputStream或BufferedWriter进行缓冲。

public class Main{
    public static void main(String[] args) {
      try{
          URL u=new URL("http://www.baidu.com?");
          URLConnection uc=u.openConnection();
          uc.setDoOutput(true);
          OutputStream raw=uc.getOutputStream();
          OutputStream bufferd=new BufferedOutputStream(raw);
          OutputStreamWriter out=new OutputStreamWriter(bufferd,"8859_1");
          out.write("first=Julie&middle=&last=Harting&work=String+Quarter\r\n");
          out.flush();
          out.close();
          //开始连接
          uc.connect();
          BufferedReader in=new BufferedReader(new InputStreamReader(uc.getInputStream(),"utf-8"));
          String line=null;
          StringBuffer rest=new StringBuffer();
          while (null != (line=in.readLine())){
                rest.append(line);
          }
          System.out.println(rest.toString());
      }catch(IOException e){
          System.err.print(e);
      }
    }
}

下面是百度的响应输出:
在这里插入图片描述
利用POST发送数据和GET几乎一样,区别是我们利用POST方法是通过URLConnection的getOutputStream()方法写入查询字符串,而不是附加到URL。java会缓冲写入输出流的所有数据,直到流关闭。所以只要你能控制客户端和服务器,就可以使用你喜欢的任何其他数据编码方式。

下面这段程序使用URLConnection类和QueryString类来提交POST表单数据,构造函数设置了URL。查询字符串是使用add方法来构建的。post()方法具体向服务器发送数据,它打开与指定URL的URLConnection,设置其doOutput字段为true,并将查询字符串写入输出流,然后返回包含服务器响应的输入流。

public class Main{
    public static void main(String[] args) throws IOException {
      URL url;
      try{
          url=new URL("http://www.cafeaulait.org/books/jnp4/postquery.phtml");
      }catch(MalformedURLException ex){
          System.err.println("Usage: java FormPoster url");
          return;
      }
       FormPoster poster=new FormPoster(url);
       poster.add("name","jakiechai");
       poster.add("email","elharo@ibiblio.org");
       try(InputStream in=poster.post()){
           Reader r=new InputStreamReader(in);
           int c;
           while((c=r.read())!=-1){
               System.out.print((char)c);
           }
           System.out.println();
       }
    }
   
    
}
class FormPoster{
    private URL url;
    static String val="";
    public FormPoster(URL url){
       if(!url.getProtocol().toLowerCase().startsWith("http"))
       {
            throw new IllegalAccessError("Posting only works for http URLs");
       }
       this.url=url;
    }
    public void add(String name,String value){
        val+=name+":"+value;
    }
    public InputStream post() throws IOException{
        URLConnection uc=url.openConnection();
        uc.setDoOutput(true);
        try(OutputStreamWriter out=new OutputStreamWriter(uc.getOutputStream(),"UTF-8")){
            out.write(val);
            out.write("\r\n");
            out.flush();
        }
        return uc.getInputStream();
    }
}

下面是服务器返回的内容:

Query Results

Query Results

You submitted the following name/value pairs:

  • name:jakiechaiemail:elharo@ibiblio_org =

The request included the following cookies:

    Here's the HTTP request header:

      
    USER_AGENT: Java/1.8.0_332
    HOST: www.cafeaulait.org
    ACCEPT: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
    X_FORWARDED_PROTO: http
    X_FORWARDED_FOR: 106.15.224.186
    CONNECTION: close
    

    Here's the complete body of the request:

    name:jakiechaiemail:elharo@ibiblio.org
    

    Some links:

    This Page Another Page
    Last Modified July 25, 2004

    在这里插入图片描述

    上面方法的核心是POST方法,它首先打开一个连接,指向存储在url字段中的URL。由于这个URLConnection需要发送输出。所以post()方法将这个连接的doOutput字段设置为true,然后将这个URL的OutputStream串联到一个发送数据的ASCII的OutputStreamWriter,接下来刷新输出并关闭流,流不关闭就不会发送任务数据。最后返回InputStream获得服务器响应。下面总结一下表单提交的步骤:

    • 确定要发送给服务器的名-值对
    • 编写接受和处理请求的服务端程序。如果没有使用定制的数据编码,可以使用普通的HTML表单和WEB浏览器测试这个程序
    • 在Java程序中创建一个查询字符串。字符串的形式如下:
      name=value1&name2=value2&jname3=value3
      在增加到查询字符串之前,先将各个名和值传递到URLEncoder.encode()
    • 打开一个URLConnection,指向接受数据的程序URL
    • 将查询字符串写入到URLConnection的OutputStream
    • 关闭URLConnection的OutputStream
    • 从URLConnection的Input Stream读取服务器的响应

    getOutputStream方法还可以用于PUT请求方法,这是一种在WEB服务器上存储文件的方法。要存储的数据写入getOutputStream返回的OutputStream。不过,这只能在URLConnection的HttpURLConnection子类中进行。

    3. URLConnection的安全考虑

    建立网络连接,读/写文件等存在一些常见的安全限制,URLConnection对象会受到这些安全限制的约束。在尝试连接一个URL前,你可能想知道是否运行连接。为此URLConnection类包含了一个getPermission()方法

    public Permission getPermission()throws IOException
    

    它返回一个Java.security.Permission对象,指出连接这个URL所需的权限。如果不需要任何权限就会返回null。URLConnection的子类会返回java.security.Permission的不同子类。

    Permission 类的主要目的是描述对于系统资源的访问权限。这些系统资源可以是文件、网络连接、操作系统功能等。通过使用权限,Java 应用程序可以定义和强制执行安全策略,以控制对敏感资源的访问。Permission 类是一个抽象类,它定义了权限的基本属性和行为,包括权限的名称、描述、是否允许操作等。具体的权限类(如 FilePermission、SocketPermission 等)是 Permission 类的子类,用于表示特定类型的权限。在 Java 安全模型中,权限由权限名和可选的操作列表组成。权限名是一个字符串,用于标识权限的类型和资源的标识符。操作列表表示对资源所允许的操作,如读取、写入、执行等。权限的粒度可以根据需要进行调整,以满足具体的安全需求。通过使用权限对象,可以进行权限检查,以确保应用程序在访问敏感资源之前具有适当的权限。这有助于提供安全性和防止恶意操作。下面是 Permission 类的一些常用方法:

    • getName():获取权限的名称。
    • getActions():获取权限的操作列表。
    • implies(Permission p):检查当前权限是否包含指定的权限。
    • equals(Object obj):比较两个权限对象是否相等。
    • hashCode():获取权限对象的哈希码值。
    • toString():返回权限对象的字符串表示。

    总结来说,java.security.Permission 类提供了一种标准化的方式来表示和管理 Java 应用程序的访问权限。它是 Java 安全模型的核心组件之一,用于实现安全策略和保护敏感资源。

    public static void main(String[] args) throws IOException {
           URL u = new URL("\n" +
                   "https://hm.baidu.com/hm.gif?hca=36FB9E633015756B&cc=1&ck=1&cl=24-bit&ds=1920x1080&vl=1001&ep=7111%2C2543&et=10&ja=0&ln=zh-cn&lo=0&lt=1684721081&rnd=108138644&si=6bcd52f51e9b3dce32bec4a3997715ac&su=https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DQUDdVYc4ExLePOefaclpkkQyDsywEmMmz4W37KJFhafJByp_lyapL-JzapNuyFy2rK_qZJfRbkQ6CuWmXotAc4dSqZuZENMBepfFjFjxwdq%26wd%3D%26eqid%3D95614ab00000085400000005646f571f&v=1.3.0&lv=3&sn=52924&r=0&ww=705&p=islogin*1*1!isonline*1*1!isvip*0*1!uid_*qq_43456605*1!view_h_*914&u=https%3A%2F%2Fblog.csdn.net%2Fqq_44231797%2Farticle%2Fdetails%2F121343892 ");
    
           URLConnection ur=u.openConnection();
            System.out.println(ur.getPermission());
        }
    

    在这里插入图片描述

    java.net.SocketPermission 是 java.security.Permission 的一个具体子类,用于表示对网络套接字的权限。它允许应用程序控制对指定主机和端口的网络连接和解析操作。在给定的示例中,“hm.baidu.com:80” 表示要访问的目标主机和端口。它指定了主机名为 hm.baidu.com,端口号为 80,这是 HTTP 协议的默认端口。“connect,resolve” 是指对该主机和端口所允许的操作。具体来说:connect 表示允许建立网络连接。应用程序可以与指定的主机和端口进行网络通信。resolve 表示允许解析主机名。应用程序可以将主机名解析为 IP 地址。

    4. HttpURLConnection

    java.net.HttpURLConnection类就是URLConnection的抽象子类。它提供了另外一些方法,在处理http URL时尤其有帮助。具体地,它包含的方法可以获得和设置请求方法,确定是否重定向、获取响应码和消息,以及确定是否使用了代理服务器。它还包括了几十个便于记忆的常量,对于各种HTTP响应码。最后,它覆盖了URLConnection超类的getPermission方法。由于这个类是抽象类,唯一的构造函数是保护类型的,所以不能直接创建HttpURLConnection实例及。不过使用http URL构造一个URL对象并调用其Openconnection方法,返回的URLConnection就是HttpURLConnection的一个实例。可以将其强转为HttpURLConnection

    URL u=new URL("http://lesswrong.com/
    URLConnection uc=u.openConnection()
    HttpURLConnection http=(HttpURLConnection) uc;
    

    默认情况下HttpURLConnection会使用GET方法,不过,可以用setRequestMethod来改变请求方法

    public void setRequestMethod(String method)throws ProtocolException
    

    这个方法的参数应当是以下7个字符串之一(区分大小写)

    • GET
    • POST
    • HEAD
    • PUT
    • DELETE
    • OPTIONS(向web服务器询问一个指定URL支持的选项列表)
    • TRACE

    当然单纯的调用setRequestMethod设置请求参数效果是不够的,更多的还需要设置我们的请求头消息

    tips:connect方法和openConnection方法的区别
    url.openConnection() 和 url.connect() 是 Java 中用于建立与指定 URL 的连接的两种方式,它们有一些区别。
    url.openConnection():

    1. url.openConnection() 是 URL 类的一个方法,它返回一个 URLConnection 对象,用于建立与指定 URL 的连接。
    2. URLConnection 是一个抽象类,具体的实现类根据 URL 的协议不同而有所不同,比如对于 HTTP 协议可以返回 HttpURLConnection 的实例。
    3. openConnection() 方法返回的 URLConnection 对象可以通过设置请求头、请求方法、读取响应等方式进行更多的控制和操>作。
    4. openConnection() 方法只是建立了与指定 URL 的连接,实际的网络通信在后续的操作中进行,比如读取输入流或写入输出流。

    url.connect():

    1. url.connect() 是 URL 类的一个方法,它是一个简单的调用,用于显式地建立与指定 URL 的连接。
    2. 它实际上是 openConnection() 方法的一个隐式调用,即在调用 connect() 时会自动执行 openConnection()。
    3. connect() 方法在建立连接后立即返回,不会返回具体的连接对象,因此无法对连接进行更多的控制和操作。
    4. connect() 方法适用于简单的连接场景,不需要对连接进行进一步配置和控制的情况。

    总结来说,url.openConnection() 返回一个具体的 URLConnection 对象,可以对连接进行更多的控制和操作,而 url.connect() 是 openConnection() 方法的简化调用,用于简单的连接场景,无需额外的配置和操作。

    HEAD
    HEAD和GET非常类似,它告诉服务器只返回HTTP首部,不用实际发送文件,这个方法最常用的是检查文件在最后一次缓存之后是否有修改。

    public class QuizCardBuilder {
    
        public static void main(String[] args) throws IOException {
            URL url;
            try{
                url=new URL("http://www.baidu.com");
                HttpURLConnection http=(HttpURLConnection) url.openConnection();
                http.setRequestMethod("HEAD");
                System.out.println(url+"was last modified at"+new Date(http.getLastModified()));
                Map<String, List<String>> map = http.getHeaderFields();
                for (Map.Entry<String, List<String>> entry : map.entrySet()) {
                    System.out.println("Key : " + entry.getKey() +
                            " ,Value : " + entry.getValue());
                }
            }catch(MalformedURLException ex){
                System.err.println("Usage: java FormPoster url");
            }
    
        }
    }
    

    在这里插入图片描述
    DELETE
    DELETE方法将删除WEB服务器上位于指定URL得文件,由于这个请求存在明显的安全风险,所以不是所有的服务器都支持该方法,即便支持,也要进行一定的身份认证。
    PUT
    许多HTML编辑器和其他希望在Web服务器上存储文件的程序会使用PUT方法,这个方法允许客户端将文档放在网站的抽象层次结构中,而不需要知道网站如果映射到实际本地文件系统的。这正与FTP相反,FTP需要知道实际的目录结构,而不是服务器的抽象结构。同样DELETE一样它也是不安全的。
    OPTIONS
    该请求方法询问某个特定的URL支持哪些选项,如果请求的URL是星号,那么这个请求会应用到整个服务器而不是服务器上的某个URL。服务器响应OPTIONS,会发送一个HTTP首部以及这个URL上允许的命令列表。

    在这里插入图片描述

    TRACE
    该方法会发送HTTP首部,服务器将从客户端接受这个HTTP首部。之所以需要这个信息,主要原因是要查看服务器和客户端之间的代理服务器做了哪些修改。

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值