詳解java如何實(shí)現(xiàn)帶RequestBody傳Json參數(shù)的GET請(qǐng)求
在調(diào)試Fate平臺(tái)時(shí),我遇到了一個(gè)奇葩的接口類型。該接口為Get方式,入?yún)⑹且粋€(gè)json類型在body中傳遞。我非常費(fèi)解使用body中傳參的話為什么不用POST請(qǐng)求而使用了GET請(qǐng)求?
在本篇文章中加入了自己對(duì)這個(gè)問(wèn)題的一點(diǎn)理解,以及通過(guò)java請(qǐng)求這個(gè)接口的完整可使用案例。(包括返回string類型和文件流類型)
一、接口調(diào)用方法

當(dāng)我看到這個(gè)接口的時(shí)候,我是有點(diǎn)懵的。Get請(qǐng)求為什么要采用這樣的參數(shù)傳遞方式,一般來(lái)說(shuō)GET請(qǐng)求就直接將參數(shù)拼接在URL中了。
二、傳參方式的討論
GET和POST請(qǐng)求和其常見(jiàn)的傳參方式
我們知道GET和POST請(qǐng)求是HTTP協(xié)議中的兩種最常用的請(qǐng)求方式,它們?cè)谔幚韰?shù)和數(shù)據(jù)傳輸方面差距還是比較大的。
參數(shù)傳遞方式:GET請(qǐng)求的參數(shù)直接附加在URL的末尾,而POST請(qǐng)求的參數(shù)則包含在請(qǐng)求體中。
這意味著GET請(qǐng)求的參數(shù)是明文傳輸?shù)?,因此在?qǐng)求過(guò)程中可能會(huì)被記錄或泄露。而POST請(qǐng)求的參數(shù)則是加密的,相對(duì)更安全。
參數(shù)的數(shù)據(jù)類型:GET請(qǐng)求的參數(shù)只能發(fā)送簡(jiǎn)單的字符串,而POST請(qǐng)求可以發(fā)送復(fù)雜的數(shù)據(jù)類型,如表單數(shù)據(jù)、JSON數(shù)據(jù)等。
這使得POST請(qǐng)求相比GET請(qǐng)求在傳遞復(fù)雜數(shù)據(jù)時(shí)更為方便和靈活。
請(qǐng)求的語(yǔ)義:GET請(qǐng)求通常用于獲取或檢索數(shù)據(jù),而POST請(qǐng)求則用于提交數(shù)據(jù)或執(zhí)行某些操作。
緩存機(jī)制:GET請(qǐng)求默認(rèn)開(kāi)啟瀏覽器緩存機(jī)制,因?yàn)樗闹饕康氖谦@取數(shù)據(jù),而POST請(qǐng)求則默認(rèn)禁用緩存機(jī)制,因?yàn)樗赡軐?duì)服務(wù)器上的資源進(jìn)行修改。
參數(shù)長(zhǎng)度限制:由于GET請(qǐng)求的參數(shù)附加在URL上,因此參數(shù)長(zhǎng)度受到URL長(zhǎng)度的限制。而POST請(qǐng)求的參數(shù)放在請(qǐng)求體中,理論上沒(méi)有長(zhǎng)度限制,但實(shí)際上服務(wù)器和客戶端可能會(huì)有最大長(zhǎng)度限制。
3、4、5意味著根據(jù)不同的需求,選擇合適的請(qǐng)求方式是很重要的。
其實(shí)GET帶使用body中傳參,從請(qǐng)求方面講符合了GET請(qǐng)求的語(yǔ)義(獲取和檢索數(shù)據(jù))有能應(yīng)用到混存機(jī)制。從參數(shù)方面講有能突破長(zhǎng)度和數(shù)據(jù)類型的限制,同時(shí)參數(shù)傳遞更安全。
GET使用請(qǐng)求體傳參的合理性
對(duì)于GET請(qǐng)求通過(guò)body傳參的情況可以說(shuō)非常罕見(jiàn),很多老java都沒(méi)見(jiàn)過(guò),也算是給我開(kāi)了眼了。
根據(jù)以往的經(jīng)驗(yàn),我們約定俗成,GET傳參通過(guò)URL拼接,POST傳參通過(guò)body傳輸。于是有些HTTP庫(kù)(如OkHttp)是不允許GET請(qǐng)求帶有請(qǐng)求體的,默認(rèn)通過(guò)post傳請(qǐng)求體。
雖然官方不推薦這樣做,但是,http(基于tcp的超文本傳輸協(xié)議)并沒(méi)有規(guī)定Get請(qǐng)求不能加body。
所以這個(gè)請(qǐng)求自有其合理性。
三、java實(shí)現(xiàn)GET使用請(qǐng)求體傳參請(qǐng)求的技術(shù)選型
在公司封裝好的Http請(qǐng)求方法類中,我們采用的是OkHttp,很不幸的是他不支持GET使用請(qǐng)求體傳參。
于是通過(guò)網(wǎng)絡(luò)搜索,我們選定了兩個(gè)方法。一個(gè)是AsyncHttpClient,另一個(gè)是apache.http.client。
參考文檔:
解決HTTP GET方法調(diào)用帶有body問(wèn)題
httpclient實(shí)現(xiàn)HttpGet請(qǐng)求傳body的json參數(shù)的
考慮到我們沒(méi)有異步請(qǐng)求方面的需求,于是最后選定了apache.http.client
四、完整實(shí)現(xiàn)
1.pom引入關(guān)鍵依賴
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.6</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.5.6</version> </dependency>
2.定義HttpGet實(shí)體類
這個(gè)實(shí)體類主要供后續(xù)實(shí)現(xiàn)的方法類調(diào)用,可以單獨(dú)作為一個(gè)類,也可以將其作為方法類的子類。
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import java.net.URI;
public class HttpGetWithEntity extends HttpEntityEnclosingRequestBase {
private final static String METHOD_NAME = "GET";
public HttpGetWithEntity() {
super();
}
public HttpGetWithEntity(final URI uri) {
super();
setURI(uri);
}
HttpGetWithEntity(final String uri) {
super();
setURI(URI.create(uri));
}
@Override
public String getMethod() {
return METHOD_NAME;
}
}
3.實(shí)現(xiàn)方法類
這里實(shí)現(xiàn)了兩個(gè)方法,都是通過(guò)GET請(qǐng)求傳遞請(qǐng)求體數(shù)據(jù)的(請(qǐng)求體數(shù)據(jù)已轉(zhuǎn)換為為JsonString)。
區(qū)別在于一個(gè)是正常返回String類型Response。另一個(gè)是返回文件流并將文件流寫(xiě)入到文件中。
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@Slf4j
public class ApacheHttpUitls {
public static String getResponseByJson(String url, String param, String encoding) throws Exception {
String body = "";
//創(chuàng)建httpclient對(duì)象
CloseableHttpClient client = HttpClients.createDefault();
HttpGetWithEntity httpGetWithEntity = new HttpGetWithEntity(url);
HttpEntity httpEntity = new StringEntity(param, ContentType.APPLICATION_JSON);
httpGetWithEntity.setEntity(httpEntity);
//執(zhí)行請(qǐng)求操作,并拿到結(jié)果
CloseableHttpResponse response = client.execute(httpGetWithEntity);
//獲取結(jié)果實(shí)體
HttpEntity entity = response.getEntity();
if (entity != null) {
//按指定編碼轉(zhuǎn)換結(jié)果實(shí)體為String類型
body = EntityUtils.toString(entity, encoding);
}
//釋放鏈接
response.close();
return body;
}
public static boolean getStreamGetResponse(String url, String requestBody, String outputFilePath) throws Exception {
InputStream inputStream = null;
OutputStream outputStream = null;
CloseableHttpResponse response = null;
try{
//創(chuàng)建httpclient對(duì)象
CloseableHttpClient client = HttpClients.createDefault();
HttpGetWithEntity httpGetWithEntity = new HttpGetWithEntity(url);
HttpEntity httpEntity = new StringEntity(requestBody, ContentType.APPLICATION_JSON);
httpGetWithEntity.setEntity(httpEntity);
//執(zhí)行請(qǐng)求操作,并拿到結(jié)果
response = client.execute(httpGetWithEntity);
//獲取結(jié)果實(shí)體
HttpEntity entity = response.getEntity();
log.info("requestUrl: {}, requestBody: {}", url, requestBody);
if (entity != null) {
inputStream = entity.getContent();
Path path = Paths.get(outputFilePath);
if (!Files.exists(path)) {
try {
Files.createFile(path);
} catch (IOException e) {
log.error("File create error ", e);
// 處理異常,例如輸出錯(cuò)誤消息或退出程序
}
}
outputStream = Files.newOutputStream(path);
byte[] buffer = new byte[1024]; // 可以根據(jù)需要調(diào)整緩沖區(qū)大小
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
log.info("File downloaded and saved at " + outputFilePath);
}else{
log.error("Http get Entity is null");
return false;
}
return true;
} catch (Exception e){
log.error("File download error ", e);
return false;
} finally {
//釋放鏈接
if (response != null) response.close();
if (inputStream != null) inputStream.close();
if (outputStream != null) outputStream.close();
}
}
}
以上就是詳解java如何實(shí)現(xiàn)帶RequestBody傳Json參數(shù)的GET請(qǐng)求的詳細(xì)內(nèi)容,更多關(guān)于java帶RequestBody傳Json參數(shù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
完美解決java.lang.OutOfMemoryError處理錯(cuò)誤的問(wèn)題
下面小編就為大家?guī)?lái)一篇完美解決java.lang.OutOfMemoryError處理錯(cuò)誤的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01
解決SpringBoot在IDEA中熱部署失效問(wèn)題
熱部署是指程序運(yùn)行過(guò)程中實(shí)時(shí)更新或替換其組件的技術(shù),即項(xiàng)目正在啟動(dòng)中,修改了配置文件中某個(gè)值或者添加了某個(gè)方法或者修改了某個(gè)方法參數(shù),本文給大家介紹了解決SpringBoot在IDEA中熱部署失效問(wèn)題,需要的朋友可以參考下2024-01-01
理解JDK動(dòng)態(tài)代理為什么必須要基于接口
這篇文章主要介紹了理解JDK動(dòng)態(tài)代理為什么必須要基于接口,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10
JavaAgent實(shí)現(xiàn)http接口發(fā)布方式淺析
這篇文章主要介紹了JavaAgent實(shí)現(xiàn)http接口發(fā)布方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧2023-03-03
springsecurity第三方授權(quán)認(rèn)證的項(xiàng)目實(shí)踐
Spring security 是一個(gè)強(qiáng)大的和高度可定制的身份驗(yàn)證和訪問(wèn)控制框架,本文主要介紹了springsecurity第三方授權(quán)認(rèn)證的項(xiàng)目實(shí)踐,具有一定的參考價(jià)值,感興趣可以了解一下2023-08-08

