亚洲视频二区_亚洲欧洲日本天天堂在线观看_日韩一区二区在线观看_中文字幕不卡一区

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.430618.com 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

本文介紹了通過(guò)反射訪問(wèn)HttpURLConnection的私有MessageHeader字段(&Q;Autorization&Q;)的處理方法,對(duì)大家解決問(wèn)題具有一定的參考價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧!

問(wèn)題描述

目前正在為現(xiàn)有庫(kù)編寫單元測(cè)試,我正在嘗試解決here的限制,即您無(wú)法使用反射檢索已設(shè)置的授權(quán)和標(biāo)頭。

我使用的代碼是一個(gè)非常典型的代碼片段,我已經(jīng)使用了幾十次來(lái)訪問(wèn)私有字段:

HttpURLConnection conn = (HttpURLConnection) new URL("https://stackoverflow.com").openConnection();
conn.setRequestProperty("Authorization", "Basic Zm9vYmFyOnNlY3JldA==");
try {
    Field requests = conn.getClass().getSuperclass().getSuperclass().getSuperclass().getDeclaredField("requests");
    requests.setAccessible(true);
    MessageHeader headers = (MessageHeader) requests.get(conn); // Problem: returns null
    return headers.getValue(headers.getKey("Authorization"));
} catch (IllegalAccessException | NoSuchFieldException e) {
    e.printStackTrace();
}

但是-通過(guò)Field::get提取失敗并返回null(請(qǐng)參閱注釋行)。

查看HttpUrlConnection的基類URLConnection,我知道我正在尋找requests字段。通過(guò)它調(diào)試,我可以看到我想要提取的字段(甚至顯示了授權(quán)和值):

在無(wú)法返回MessageHeader對(duì)象的代碼行中,看起來(lái)我引用了URLConnection

中的字段

但我肯定遺漏了什么–有人能說(shuō)出是什么嗎?

更新

讓我困惑的是

    我只從java.net包導(dǎo)入URLConnectionHttpURLConnection這一事實(shí)。然而,從第一個(gè)調(diào)試屏幕截圖來(lái)看,conn-對(duì)象實(shí)現(xiàn)顯然來(lái)自sun.net.www.protocol.https
    DelegateHttpsURLConnection成員(也顯示在第一個(gè)調(diào)試截圖中)

推薦答案

當(dāng)您在對(duì)象上調(diào)用getClass()時(shí),您將獲得其實(shí)際的運(yùn)行時(shí)類型,該類型不必與編譯時(shí)類型匹配,因?yàn)樗赡苁撬淖宇悺R虼耍ㄟ^(guò)getSuperclass()遍歷類層次結(jié)構(gòu)是很脆弱的。

當(dāng)您知道預(yù)先聲明了字段的類時(shí),您可以只使用該類,例如

HttpURLConnection conn = (HttpURLConnection)
    new URL("https://stackoverflow.com").openConnection();
try {
  Field f = URLConnection.class.getDeclaredField("requests");
  f.setAccessible(true);
  System.out.println(f.get(conn));
}
catch(ReflectiveOperationException ex) {
  ex.printStackTrace();
}

但是,這將始終打印null,因?yàn)檫@個(gè)特定的連接實(shí)現(xiàn)不使用其超類狀態(tài),而是委托給不同的實(shí)現(xiàn)。正如您自己發(fā)現(xiàn)的那樣,它存儲(chǔ)在一個(gè)名為delegate的字段中。

HttpURLConnection conn = (HttpURLConnection)
    new URL("https://stackoverflow.com").openConnection();
for(Class<?> c = conn.getClass(); c != URLConnection.class; c = c.getSuperclass())
  System.out.print(c.getName() + " > ");
System.out.println(URLConnection.class.getName());

Field delegate = conn.getClass().getDeclaredField("delegate");
delegate.setAccessible(true);
conn = (HttpURLConnection)delegate.get(conn);

for(Class<?> c = conn.getClass(); c != URLConnection.class; c = c.getSuperclass())
  System.out.print(c.getName() + " > ");
System.out.println(URLConnection.class.getName());

Field requests = URLConnection.class.getDeclaredField("requests");
requests.setAccessible(true);
System.out.println(requests.get(conn));

此打印

sun.net.www.protocol.https.HttpsURLConnectionImpl > javax.net.ssl.HttpsURLConnection > java.net.HttpURLConnection > java.net.URLConnection
sun.net.www.protocol.https.DelegateHttpsURLConnection > sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection > sun.net.www.protocol.http.HttpURLConnection > java.net.HttpURLConnection > java.net.URLConnection
null

顯示這兩個(gè)對(duì)象具有不同的類層次結(jié)構(gòu),因此,假設(shè)特定深度遍歷它確實(shí)是脆弱的。

它還會(huì)再次打印null,因?yàn)榧词故沁@個(gè)實(shí)現(xiàn)類也沒有使用從URLConnection繼承的requests字段。相反,類sun.net.www.protocol.http.HttpURLConnection聲明了自己的同名字段,其中包含實(shí)際的MessageHeader對(duì)象。這就是為什么在委托的實(shí)現(xiàn)類上執(zhí)行getSuperclass().getSuperclass()會(huì)得到正確的字段,而不是URLConnection的字段。

當(dāng)我們事先知道這一點(diǎn)時(shí),我們可以使用

HttpURLConnection conn =
    (HttpURLConnection) new URL("https://stackoverflow.com").openConnection();
conn.setRequestProperty("Authorization", "Basic Zm9vYmFyOnNlY3JldA==");

Field delegate = Class.forName("sun.net.www.protocol.https.HttpsURLConnectionImpl")
    .getDeclaredField("delegate");
Field requests = Class.forName("sun.net.www.protocol.http.HttpURLConnection")
    .getDeclaredField("requests");
AccessibleObject.setAccessible(new Field[] { delegate, requests}, true);
sun.net.www.MessageHeader headers =
    (sun.net.www.MessageHeader)requests.get(delegate.get(conn));
return headers.findValue("Authorization");

因?yàn)槟鸁o(wú)論如何都要訪問(wèn)sun.net. …包,所以您可以直接引用這些類,而不是使用Class.forName,但我認(rèn)為后者在這種特定情況下更可靠,因?yàn)樗羞@些類都很容易混淆名稱,有時(shí)甚至是相同的簡(jiǎn)單名稱,只是它們的包不同。

private String getAuthorizationHeaderValue(HttpURLConnection conn) {
  try {
    Field delegate = sun.net.www.protocol.https.HttpsURLConnectionImpl.class.getDeclaredField("delegate");
    Field requests = sun.net.www.protocol.http.HttpURLConnection.class.getDeclaredField("requests");
    AccessibleObject.setAccessible(new Field[] { delegate, requests}, true);
    sun.net.www.MessageHeader headers = (sun.net.www.MessageHeader)requests.get(delegate.get(conn));
    return headers.findValue("Authorization");
  } catch(ReflectiveOperationException ex) {
    ex.printStackTrace();
    return "";
  }
}

這篇關(guān)于通過(guò)反射訪問(wèn)HttpURLConnection的私有MessageHeader字段(&Q;Autorization&Q;)的文章就介紹到這了,希望我們推薦的答案對(duì)大家有所幫助,

分享到:
標(biāo)簽:Autorization HttpURLConnection MessageHeader 反射 字段 私有 訪問(wèn)
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定