欧美一级特黄大片做受成人-亚洲成人一区二区电影-激情熟女一区二区三区-日韩专区欧美专区国产专区

怎樣解決SpringRestTemplatepost傳遞參數(shù)時(shí)報(bào)錯(cuò)問題

怎樣解決SpringRestTemplatepost傳遞參數(shù)時(shí)報(bào)錯(cuò)問題,相信很多沒有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個(gè)問題。

創(chuàng)新互聯(lián)專注于企業(yè)成都營(yíng)銷網(wǎng)站建設(shè)、網(wǎng)站重做改版、瓊山網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5開發(fā)、商城網(wǎng)站開發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為瓊山等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

RestTemplate的post參數(shù)為什么使用MultiValueMap而不能使用HashMap?

今天跟同事接口聯(lián)調(diào),使用RestTemplate請(qǐng)求服務(wù)端的post接口(使用python開發(fā))。詭異的是,post請(qǐng)求,返回500 Internal Server Error,而使用get請(qǐng)求,返回正常。代碼如下:

HashMap<String, Object> hashMap = Maps.newHashMap(); hashMap.put("data", JSONObject.toJSONString(params)); url = "http://mydomain/dataDownLoad.cgi?data={data}"; json = restTemplate.getForObject(url, String.class, hashMap); System.out.println("get json : " + json); url = "http://mydomain/dataDownLoad.cgi"; json = restTemplate.postForObject(url, hashMap, String.class); System.out.println("hasmap post json : " + json);

結(jié)果為:

get json : {'status': 0, 'statusInfo': {'global': 'OK'}, 'data': 'http://mydomain/dataDownLoad.cgi?downLoadData=358300d5f9e1cc512efc178caaa0b061'}500 Internal Server Error

最后經(jīng)過另一位同學(xué)幫忙排查,發(fā)現(xiàn)RestTemplate在postForObject時(shí),不可使用HashMap。而應(yīng)該是MultiValueMap。改為如下:

MultiValueMap<String, String> paramMap = new LinkedMultiValueMap<>();paramMap.add("data", JSONObject.toJSONString(params));url = "http://mydomain/dataDownLoad.cgi";json = restTemplate.postForObject(url, paramMap, String.class);System.out.println("post json : " + json);

結(jié)果為:

post json : {'status': 0, 'statusInfo': {'global': 'OK'}, 'data': 'http://mydomain/dataDownLoad.cgi?downLoadData=f2fc328513886e51b3b67d35043985ae'}

然后我想起之前使用RestTemplate發(fā)起post請(qǐng)求時(shí),使用POJO作為參數(shù),是可行的。再次測(cè)試:

url = "http://mydomain/dataDownLoad.cgi";PostData postData = new PostData();postData.setData(JSONObject.toJSONString(params));json = restTemplate.postForObject(url, paramMap, String.class);System.out.println("postData json : " + json);

返回:500 Internal Server Error。

到現(xiàn)在為止接口調(diào)通了。但問題的探究才剛剛開始。

RestTemplate的post參數(shù)為什么使用MultiValueMap而不能使用HashMap?

為什么post接口,get請(qǐng)求也可以正確返回?

為什么java服務(wù)端可以接收POJO參數(shù),python服務(wù)端不可以?python服務(wù)端使用CGI(Common Gateway Interface),與cgi有關(guān)系嗎?

何為MultiValueMap

IDEA中command+N,搜索類MultiValueMap,發(fā)現(xiàn)apache的commons-collections包有一個(gè)MultiValueMap類,spring-core包中有一個(gè)接口MultiValueMap,及其實(shí)現(xiàn)類LinkedMultiValueMap。顯然看spring包。

首先看LinkedMultiValueMap,實(shí)現(xiàn)MultiValueMap接口,只有一個(gè)域:Map<K, List<V>> targetMap = new LinkedHashMap<K, List<V>>()。 其中value為new LinkedList<V>()。再看接口方法:

public interface MultiValueMap<K, V> extends Map<K, List<V>> {  V getFirst(K key); //targetMap.get(key).get(0)  void add(K key, V value); //targetMap.get(key).add(value)  void set(K key, V value); //targetMap.set(key, Lists.newLinkedList(value))  void setAll(Map<K, V> values); //將普通map轉(zhuǎn)為L(zhǎng)inkedMultiValueMap  Map<K, V> toSingleValueMap(); //只保留所有LinkedList的第一個(gè)值,轉(zhuǎn)為L(zhǎng)inkedHashMap}

綜上,LinkedMultiValueMap實(shí)際就是Key-LinkedList的map。

RestTemplate怎么處理post參數(shù)

首先查看RestTemplate源碼,首先將請(qǐng)求封裝成HttpEntityRequestCallback類對(duì)象,然后再處理請(qǐng)求。

Overridepublic <T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables)    throws RestClientException {  //請(qǐng)求包裝成httpEntityCallback  RequestCallback requestCallback = httpEntityCallback(request, responseType);  HttpMessageConverterExtractor<T> responseExtractor =      new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger);  //處理請(qǐng)求     return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);}

那么HttpEntityRequestCallback是什么樣的呢?如下,實(shí)際是把請(qǐng)求數(shù)據(jù)放在了一個(gè)HttpEntity中。如果requestBody是HttpEntity類型,就直接轉(zhuǎn);否則,放在HttpEntity的body中。

//請(qǐng)求內(nèi)容封裝在一個(gè)HttpEntity對(duì)象中。private HttpEntityRequestCallback(Object requestBody, Type responseType) {  super(responseType);  if (requestBody instanceof HttpEntity) {    this.requestEntity = (HttpEntity<?>) requestBody;  }  else if (requestBody != null) {    this.requestEntity = new HttpEntity<Object>(requestBody);  }  else {    this.requestEntity = HttpEntity.EMPTY;  }}

接著看一下HttpEntity源碼:

public class HttpEntity<T> {  private final HttpHeaders headers;  private final T body;  public HttpEntity(T body) {    this.body = body;  }}public class HttpHeaders implements MultiValueMap<String, String>, Serializable{  ......}

至此,與MultiValueMap聯(lián)系上了。

基于本次問題,我們不考慮post數(shù)據(jù)參數(shù)是HttpEntity類型的,只考慮普通POJO。那么,postForObject中對(duì)post數(shù)據(jù)的第一步處理,就是放在一個(gè)HttpEntity類型(header為MultiValueMap類型,body為泛型)的body中。

再看處理請(qǐng)求的部分:

Object requestBody = requestEntity.getBody();Class<?> requestType = requestBody.getClass();HttpHeaders requestHeaders = requestEntity.getHeaders();MediaType requestContentType = requestHeaders.getContentType();for (HttpMessageConverter<?> messageConverter : getMessageConverters()) {  if (messageConverter.canWrite(requestType, requestContentType)) {    if (!requestHeaders.isEmpty()) {      httpRequest.getHeaders().putAll(requestHeaders);    }    ((HttpMessageConverter<Object>) messageConverter).write(        requestBody, requestContentType, httpRequest);    return;  }}

通過配置的HttpMessageConverter來處理。

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">    <constructor-arg ref="ky.clientHttpRequestFactory"/>    <property name="errorHandler">      <bean class="org.springframework.web.client.DefaultResponseErrorHandler"/>    </property>    <property name="messageConverters">      <list>        <bean class="org.springframework.http.converter.FormHttpMessageConverter"/>        <bean class="cn.com.autodx.common.jsonView.ViewAwareJsonMessageConverter"/>        <bean class="org.springframework.http.converter.StringHttpMessageConverter">          <property name="supportedMediaTypes">            <list>              <value>text/html;charset=UTF-8</value>              <value>application/json</value>            </list>          </property>        </bean>      </list>    </property>  </bean>

符合要求的只有ViewAwareJsonMessageConverter,其自定義處理如下。post數(shù)據(jù)中hashMap只含有data一個(gè)key,不含status字段,所以會(huì)跳過寫的操作,即post請(qǐng)求帶不上參數(shù)。如果修改代碼,當(dāng)不含status字段時(shí),按照父類方法處理,則服務(wù)端可以得到參數(shù)。

protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {  if(object instanceof Map) {    Map map = (Map)object;    HashMap statusInfo = new HashMap();    //不含有status字段,跳過    Object status = map.get("status");    if(status != null) {      int code = Integer.parseInt(String.valueOf(status));      if(0 != code) {        super.writeInternal(object, outputMessage);      } else {        statusInfo.put("global", "OK");        map.put("statusInfo", statusInfo);        super.writeInternal(object, outputMessage);      }    }  } else {    super.writeInternal(object, outputMessage);  }}

而使用MultiValueMap會(huì)由FormHttpMessageConverter正確處理。

首先判斷是否可以執(zhí)行寫操作,如果可以,執(zhí)行寫操作。

@Override  public boolean canWrite(Class<?> clazz, MediaType mediaType) {    if (!MultiValueMap.class.isAssignableFrom(clazz)) {      return false;    }    if (mediaType == null || MediaType.ALL.equals(mediaType)) {      return true;    }    for (MediaType supportedMediaType : getSupportedMediaTypes()) {      if (supportedMediaType.isCompatibleWith(mediaType)) {        return true;      }    }    return false;  }@Override@SuppressWarnings("unchecked")public void write(MultiValueMap<String, ?> map, MediaType contentType, HttpOutputMessage outputMessage)    throws IOException, HttpMessageNotWritableException {  if (!isMultipart(map, contentType)) { //LinkedList中是否含有多個(gè)數(shù)據(jù)    //只是普通的K-V,寫form    writeForm((MultiValueMap<String, String>) map, contentType, outputMessage);  }  else {    writeMultipart((MultiValueMap<String, Object>) map, outputMessage);  }}

既如此,那么post參數(shù)為POJO時(shí),如何呢?

POJO也會(huì)被ViewAwareJsonMessageConverter處理,在其writeInternal中,object不是map,所以調(diào)用 super.writeInternal(object, outputMessage),如下:

@Overrideprotected void writeInternal(Object obj, HttpOutputMessage outputMessage) throws IOException,                              HttpMessageNotWritableException {  OutputStream out = outputMessage.getBody();  String text = JSON.toJSONString(obj, features);  byte[] bytes = text.getBytes(charset);  out.write(bytes);}

如果注釋掉ViewAwareJsonMessageConverter,跟蹤發(fā)現(xiàn),會(huì)報(bào)錯(cuò),返回沒有合適的HttpMessageConverter處理。

使用ViewAwareJsonMessageConverter和使用FormHttpMessageConverter寫數(shù)據(jù)的格式是不一樣的,所以,post POJO后,會(huì)返回錯(cuò)誤,但實(shí)際已將參數(shù)傳遞出去。

所以,對(duì)于我們配置的RestTemplate來說,post參數(shù)可以是map(有字段要求),也可以是POJO。即,輸入輸出數(shù)據(jù)由RestTemplate配置的messageConverters決定。

至此,我們已經(jīng)清楚了第一個(gè)問題,剩下的問題同樣的思路。跟蹤一下getForObject的處理路徑。get方式請(qǐng)求時(shí),把所有的參數(shù)拼接在url后面,發(fā)給服務(wù)端,就可以把參數(shù)帶到服務(wù)端。

剩下的問題就是python服務(wù)端是怎么處理請(qǐng)求的。首先研究一下CGI。

何為CGI

通用網(wǎng)關(guān)接口(CGI,Common Gateway Interface)是一種Web服務(wù)器和服務(wù)器端程序進(jìn)行交互的協(xié)議。CGI完全獨(dú)立于編程語(yǔ)言,操作系統(tǒng)和Web服務(wù)器。這個(gè)協(xié)議可以用vb,c,php,python 來實(shí)現(xiàn)。

工作方式如圖所示:

browser->webServer: HTTP protocol

webServer->CGI腳本: 通過CGI管理模塊調(diào)用腳本

CGI腳本->CGI腳本: 執(zhí)行腳本程序

CGI腳本->webServer: 返回結(jié)果

webServer->browser: HTTP protocol

web服務(wù)器獲取了請(qǐng)求cgi服務(wù)的http請(qǐng)求后,啟動(dòng)cgi腳本,并將http協(xié)議參數(shù)和客戶端請(qǐng)求參數(shù)轉(zhuǎn)為cgi協(xié)議的格式,傳給cgi腳本。cgi腳本執(zhí)行完畢后,將數(shù)據(jù)返回給web服務(wù)器,由web服務(wù)器返回給客戶端。

cgi腳本怎么獲取參數(shù)呢?

CGI腳本從環(huán)境變量QUERY_STRING中獲取GET請(qǐng)求的數(shù)據(jù)

CGI腳本從stdin(標(biāo)準(zhǔn)輸入)獲取POST請(qǐng)求的數(shù)據(jù),數(shù)據(jù)長(zhǎng)度存在環(huán)境變量CONTENT_LENGTH中。

了解CGI大概是什么東東后,看一下python實(shí)現(xiàn)的CGI。

python的CGI模塊,要獲取客戶端的post參數(shù),可以使用cgi.FieldStorage()方法。FieldStorage相當(dāng)于python中的字典,支持多個(gè)方法??梢灾С忠话愕膋ey-value,也可以支持key-List<Value>,即類似于MultiValueMap形式的參數(shù)(如多選的表單數(shù)據(jù))。

看完上述內(nèi)容,你們掌握怎樣解決SpringRestTemplatepost傳遞參數(shù)時(shí)報(bào)錯(cuò)問題的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!

分享文章:怎樣解決SpringRestTemplatepost傳遞參數(shù)時(shí)報(bào)錯(cuò)問題
分享地址:http://aaarwkj.com/article22/gjoscc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供ChatGPT軟件開發(fā)、手機(jī)網(wǎng)站建設(shè)企業(yè)網(wǎng)站制作、電子商務(wù)響應(yīng)式網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

微信小程序開發(fā)
亚洲欧美午夜福利视频| 国产日产精品久久婷婷色| 亚洲午夜精品久久久天堂 | 欧美日韩欧美国产精品| 免费看真人性生活视频| 精品国产亚洲av未满十八| 视频一区视频二区在线| 天堂av好男人亚洲精品| 亚洲另类偷拍校园伦理| 国产91黑丝视频在线观看| 亚洲成人乱码一区二区| 丁香六月色婷婷亚洲激情| 日韩高清在线不卡视频| 国产精品色呦呦一区二区| 免费国产三级在线观看| 免费在线成人av观看| 国产一区二区三区91精品| 日韩精品高清中文字幕| 麻豆久久av免费观看| 激情男女一区二区三区| 精品人妻中文字幕在线| 91久久亚洲综合精品日本| 国产一区二区三区免费有码视频| 日本一级特黄大片做受在线观看| 中文字幕日韩乱码一级在线| 成人黄色av免费看| 欧美精品青青久久久久久| 日韩夫妻性生活免费视频| 在线看电影亚洲一区| 国产精品午夜视频免费观看| 加勒比av免费在线播放| 99热这里只有精品免费播放| 久久久久久97精品| 久久亚洲精品中文字幕一| 99热精品免费在线观看| 男女搞j视频网站免费观看| 黄色日韩欧美在线观看| 久久精品国产久精国产爱| 亚洲精品黄色在线观看| 欧美精品高清在线视频| 国产情侣自拍视频在线观看|