Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to solve the problem of Times error in SpringRestTemplatepost Transmission parameters

2025-02-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

How to solve the SpringRestTemplatepost transmission parameters Times error problem, I believe that many inexperienced people do not know what to do, so this paper summarizes the causes of the problem and solutions, through this article I hope you can solve this problem.

Why does the post parameter of RestTemplate use MultiValueMap instead of HashMap?

Today, in conjunction with the interface of my colleagues, use RestTemplate to request the server's post interface (developed using python). The weird thing is that the post request returns 500 Internal Server Error, while using the get request, it returns normal. The code is as follows:

HashMap 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)

The result is:

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

Finally, with the help of another classmate, I found that when RestTemplate was in postForObject, HashMap could not be used. It should be MultiValueMap. Replace it with the following:

MultiValueMap 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)

The result is:

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

Then I remembered that when I made a post request using RestTemplate, it was possible to use POJO as a parameter. Test again:

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)

Return: 500 Internal Server Error.

Up to now, the interface has been connected. But the exploration of the problem has only just begun.

Why does the post parameter of RestTemplate use MultiValueMap instead of HashMap?

Why can the post interface and get request be returned correctly?

Why can the java server receive POJO parameters, but not the python server? The python server uses CGI (Common Gateway Interface). Does it have anything to do with cgi?

What is MultiValueMap

Command+N in IDEA, search class MultiValueMap, found that apache's commons-collections package has a MultiValueMap class, spring-core package has an interface MultiValueMap, and its implementation class LinkedMultiValueMap. Obviously, look at the spring bag.

First look at LinkedMultiValueMap, which implements the MultiValueMap interface, with only one domain: Map targetMap = new LinkedHashMap (). Where value is new LinkedList (). Take a look at the interface method:

Public interface MultiValueMap extends Map {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 values); / / convert normal map to LinkedMultiValueMap Map toSingleValueMap (); / / keep only the first value of all LinkedList, to LinkedHashMap}

To sum up, LinkedMultiValueMap is actually the map of Key-LinkedList.

What does RestTemplate do with post parameters?

First look at the RestTemplate source code, first encapsulate the request into a HttpEntityRequestCallback class object, and then process the request.

Overridepublic T postForObject (String url, Object request, Class responseType, Object... UriVariables) throws RestClientException {/ / request is packaged as httpEntityCallback RequestCallback requestCallback = httpEntityCallback (request, responseType); HttpMessageConverterExtractor responseExtractor = new HttpMessageConverterExtractor (responseType, getMessageConverters (), logger); / / processing request return execute (url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);}

So what does HttpEntityRequestCallback look like? As shown below, the request data is actually placed in a HttpEntity. If requestBody is of type HttpEntity, turn it directly; otherwise, put it in the body of HttpEntity.

/ / the request content is encapsulated in a HttpEntity object. Private HttpEntityRequestCallback (Object requestBody, Type responseType) {super (responseType); if (requestBody instanceof HttpEntity) {this.requestEntity = (HttpEntity) requestBody;} else if (requestBody! = null) {this.requestEntity = new HttpEntity (requestBody);} else {this.requestEntity = HttpEntity.EMPTY;}}

Then take a look at the HttpEntity source code:

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

At this point, I got in touch with MultiValueMap.

Based on this problem, we do not consider that the post data parameters are of type HttpEntity, only normal POJO is considered. So, the first step in dealing with post data in postForObject is to put it in a body of type HttpEntity (header is of MultiValueMap type and body is generic).

Let's take a look at the part of processing the request:

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) messageConverter). Write (requestBody, requestContentType, httpRequest); return;}}

It is handled by the configured HttpMessageConverter.

Text/html;charset=UTF-8 application/json

Only ViewAwareJsonMessageConverter meets the requirements, and its custom processing is as follows. HashMap in post data contains only data key and no status field, so the write operation is skipped, that is, the post request does not take parameters. If you modify the code and follow the parent method when there is no status field, the server can get the parameters.

Map.put ("statusInfo", statusInfo); super.writeInternal (object, outputMessage);} else {super.writeInternal (object, outputMessage);}}

Using MultiValueMap will be handled correctly by FormHttpMessageConverter.

It is first determined whether the write operation can be performed, and if so, the write operation can be performed.

@ 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 map, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {if (! isMultipart (map, contentType)) {/ / LinkedList whether there is more than one data / / just ordinary KLV, write form writeForm ((MultiValueMap) map, contentType, outputMessage);} else {writeMultipart ((MultiValueMap) map, outputMessage);}}

In that case, what if the post parameter is POJO?

POJO is also processed by ViewAwareJsonMessageConverter. In its writeInternal, object is not map, so call super.writeInternal (object, outputMessage) as follows:

@ 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);}

If the ViewAwareJsonMessageConverter is commented out, the trace finds that an error is reported and no appropriate HttpMessageConverter processing is returned.

The format of writing data using ViewAwareJsonMessageConverter is different from that of writing data using FormHttpMessageConverter, so an error is returned after post POJO, but the parameters are actually passed.

So, for the RestTemplate we configured, the post parameter can be either map (with field requirements) or POJO. That is, the input and output data is determined by the messageConverters configured by the RestTemplate.

At this point, we have made it clear that the first question and the rest are the same way of thinking. Track the processing path of getForObject. When requesting in get mode, all the parameters are concatenated after the url and sent to the server, and the parameters can be brought to the server.

The remaining question is how the python server handles the request. First, take a look at CGI.

What is CGI

Universal Gateway Interface (CGI,Common Gateway Interface) is a protocol for the interaction between Web servers and server-side programs. CGI is completely independent of programming language, operating system and Web server. This protocol can be implemented in vb,c,php,python.

The way it works is shown in the figure:

Browser- > webServer: HTTP protocol

WebServer- > CGI script: invoke the script through the CGI management module

CGI script-> CGI script: execute script

CGI script-> webServer: returns the result

WebServer- > browser: HTTP protocol

After the web server obtains the http request for the cgi service, it starts the cgi script, and converts the http protocol parameters and client request parameters into the format of cgi protocol, and passes them to the cgi script. After the cgi script is executed, the data is returned to the web server and returned to the client by the web server.

How does the cgi script get the parameters?

The CGI script gets the data requested by GET from the environment variable QUERY_STRING

The CGI script gets the data requested by POST from stdin (standard input), and the data length is stored in the environment variable CONTENT_LENGTH.

Once you know what CGI is, take a look at the CGI implemented by python.

The CGI module of python, to get the post parameters of the client, you can use the cgi.FieldStorage () method. FieldStorage is the equivalent of a dictionary in python and supports multiple methods. You can support either general key-value or key-List, that is, parameters similar to MultiValueMap (such as multi-selected form data).

After reading the above, have you mastered the method of how to solve the problem of error in passing parameters in SpringRestTemplatepost? If you want to learn more skills or want to know more about it, you are welcome to follow the industry information channel, thank you for reading!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report