spring mvc http proxy - spring-mvc

I would like to write a spring MVC Controller class that just take any http request in input, add basic authentication headers to it and forward this request to another server.
I try something like this without success.
#Controller
#RequestMapping("/proxyws")
public class ProxyController {
#RequestMapping("/**")
#ResponseBody
public String mirrorRest( #RequestBody String body, HttpMethod method, HttpServletRequest request, HttpServletResponse response) throws URISyntaxException
{
String server = "localhost";
int port = 8080;
URI uri = new URI("http", null, server, port, request.getRequestURI(), request.getQueryString(), null);
RestTemplate restTemplate=new RestTemplate();
HttpEntity entity = new HttpEntity<String>(body);
String plainCreds = "APP_CLIENT:APP_PASSWORD";
byte[] plainCredsBytes = plainCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
String base64Creds = new String(base64CredsBytes);
entity.getHeaders().add("Authorization", "Basic " + base64Creds);
ResponseEntity<String> responseEntity = restTemplate.exchange(uri, method, entity, String.class);
return responseEntity.getBody();
}
For a GET method in input, I get the following exception :
org.springframework.http.converter.HttpMessageNotReadableException: Required request body content is missing:
org.springframework.web.method.HandlerMethod$HandlerMethodParameter#8051792a
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleEmptyBody(RequestResponseBodyMethodProcessor.java:189)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:170)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:105)
For a POST request, I get other trouble with le basic auth headers:
java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableMap.put(Collections.java:1342)
at org.springframework.http.HttpHeaders.add(HttpHeaders.java:831)
Thanx for your help!

You cannot modify the headers of the HttpEntity object once it's instantiated. You need to pass your headers in through a different HttpEntity constructor, e.g.
public HttpEntity(T body, MultiValueMap<String, String> headers) {
this.body = body;
HttpHeaders tempHeaders = new HttpHeaders();
if (headers != null) {
tempHeaders.putAll(headers);
}
this.headers = HttpHeaders.readOnlyHttpHeaders(tempHeaders);
}
Note the initialization of this.headers: that's where the read-only copy is created.

Related

How to use Retrofit to upload a file with http put

I am trying to upload a file with http PUT method,
I tried with OkHttp successfully, but failed with Retrofit.
Here is my codes :
static final String MEDIA_TYPE=“image/jpeg”
// file is a file path
RequestBody requestBody = getRequestBody(file);
OkHttpClient client = getOkHttpClient();
Request request = new Request.Builder()
.url(url)
.put(requestBody)
.build();
okhttp3.Response response = response = client.newCall(request).execute();
private RequestBody getRequestBody(String filePath) {
MediaType contentType = MediaType.parse(MEDIA_TYPE);
return RequestBody.create(contentType, new File(filePath));
}
The code above succeeded.
What is the equivalent of Retrofit ?
I tried and failed :
public interface UploadFileService {
String CONTENT_TYPE = "image/jpeg";
/** base url, just for Retrofit usage demand. */
String BASE_URL = "https://not.used.net/";
/** Must be consistent with the following uploadFile annotation. */
String UPLOAD_FILE_HTTP_METHOD = "PUT";
#Multipart
#Headers("Content-Type:" + CONTENT_TYPE)
#PUT()
Observable<Response<MinaResponse<LocalAlbum.DummyResponse>>> uploadFile(#Url String url, #Part RequestBody fileBody);
}
Remove Multipart annotation and apply Body to fileBody,
I succeeded!
#Headers("Content-Type:" + CONTENT_TYPE)
#PUT()
Observable<Response<MinaResponse<LocalAlbum.DummyResponse>>> uploadFile(#Url String url, #Body RequestBody fileBody);

Spring Resttemplate : how to post file and common String data at the same time

I meet a request to upload files with spring resttemplate to upload files
with http header "multipart/form-data", also some other normal parameters need to be posted. how to implements that?
you can use the following code in your application to have both multipartfile and normal request parameters at the same time.
Replace the url with your own.
replace param and value according to your normal parameters.
String url ="http://example.com";
String fileAbsPath ="absolute path of your file";
String fileName = new File(fileAbsPath).getName();
Files.readAllBytes(Paths.get(fileAbsPath));
MultiValueMap<String, Object> data = new LinkedMultiValueMap<String, Object>();
ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(Paths.get(fileAbsPath))) {
#Override
public String getFilename() {
return fileName;
}
};
data.add("file", resource);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("file","application/pdf");
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("param1", "value1")
.queryParam("param2", "value2")
HttpEntity<> entity =
new HttpEntity<> (data, requestHeaders);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> result =restTemplate.exchange(
builder.toUriString(),
HttpMethod.POST,
entity,
String.class);
System.out.println(result.getBody());
you can use this code.
HttpHeaders headers = getCASHeaders(MediaType.MULTIPART_FORM_DATA);
LinkedMultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
params.add("fileField", new FileSystemResource(""));//get file resource
params.add("stringfield", stringPayload);
HttpEntity requestEntity = new HttpEntity<>(params, headers);
ResponseEntity<CasAssetApiResponse> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
This will send post call with two param, you can add more according to your wish.
Please have a look at this stackoverflow answer as well
I got the error "cannot be cast to java.lang.String" although my code does not have any casting.

Spring boot 1.5.7 uploading file along with params using RestTemplate

I am getting myself familiar to Springboot. We are creating this Microservice based architecture were I am trying to consume this file upload service using RestTemplate.
Basically the Serve Side API code is
#PostMapping("/upload")
public ResponseEntity<?> fileUpload(#RequestParam String appender,
#RequestParam("file") MultipartFile file) {
...
}
Now on the client side
#Override
public String attachFile(String id, MultipartFile file) {
String status = null;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> upParams = new LinkedMultiValueMap<String,
Object>();
upParams.add("appender", id);
upParams.add("file", file.getOriginalFilename());
HttpEntity<MultiValueMap<String, Object>> request =
new HttpEntity<MultiValueMap<String, Object>>(upParams, headers);
String response = restTemplate.postForObject(uploadEndPoint, request,
String.class);
return status;
}
I get this error
org.springframework.web.client.HttpServerErrorException: 500
and if I change the line to below
upParams.add("file", file);
I get Error
"Could not write JSON: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class java.io.FileDescriptor and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile[\"inputStream\"]->java.io.FileInputStream[\"fd\"])

How to send http request parameters using Jersey client

I use the following rest client implementation of jersey to consume a rest service.I am able to do it successfully.Additionally now I need to send request parameters which will be consumed as part of HttpServletRequest on the producer side.
Consumer side Jersey client code
private ClientResponse getWebClientResponse(String RESOURCE_PATH, String methodType, Object requestObj) {
WebResource webResource;
ClientResponse response = null;
try {
String environmentHost = EnvironmentUtil.resolveEnvironmentHost();
Client client = prepareClient();
String RWP_BASE_URI = environmentHost + "/workflow/rest";
webResource = client.resource(RWP_BASE_URI);
WebResource path = webResource.path(RESOURCE_PATH);
if (GET.equals(methodType)) {
response = path.type(javax.ws.rs.core.MediaType.APPLICATION_JSON).get(
ClientResponse.class);
} else if (POST.equalsIgnoreCase(methodType)) {
response = path.type(javax.ws.rs.core.MediaType.APPLICATION_JSON).post(ClientResponse.class, requestObj);
}
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
return response;
}
Producer side
#Context
public void setContext(SecurityContext context) {
this.context = context;
}
public HttpServletRequest getRequest() {
return request;
}
#Context
public void setRequest(HttpServletRequest request) {
this.request = request;
}
public String getSessionUserPID(final HttpServletRequest request,
final SecurityContext context) {
if (request.getSession(false) == null) {
final String exceptionMessage = "getSessionUserPID() failed, session NOT FOUND for this request";
final Response response = Response.status(ExceptionStatus.UNAUTHORIZED.getNumber())
.entity(exceptionMessage).build();
LOG.error(exceptionMessage);
throw new WebApplicationException(response);
}
if (context.getUserPrincipal() == null) {
final String exceptionMessage = "getSessionUserPID() failed, user principal NOT FOUND";
final Response response = Response.status(ExceptionStatus.UNAUTHORIZED.getNumber())
.entity(exceptionMessage).build();
LOG.error(exceptionMessage);
throw new WebApplicationException(response);
}
final String userPID = context.getUserPrincipal().getName();
if (userPID == null || userPID.isEmpty()) {
final String exceptionMessage = "getSessionUserPID() failed, user principal name cannot be null or empty";
final Response response = Response.status(ExceptionStatus.UNAUTHORIZED.getNumber())
.entity(exceptionMessage).build();
LOG.error(exceptionMessage);
throw new WebApplicationException(response);
}
return userPID;
}
The main intention here is currently I get user information from weblogic security context but for a particular scenario I need to pass this part of rest service request and obtain it from HttpServletRequest object.How can I obtain this from httpservletrequest
You can use QueryParam or PathParam in GET method and FormParam in the POST method for sending request parameter to the server.

how can return json using response.senderror

In my app,I use springMVC and tomcat,my controller return object,but when something wrong,I only want return some string message with content tye json,so I use response.error, but it not work,the return is a html.
my controller:
#RequestMapping(value = "{id}/{name}" ,method=RequestMethod.POST,produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody UserBean login(#PathVariable String id,#PathVariable("name") String userName,
#RequestHeader(value = "User-Agent") String user_agen,
#CookieValue(required = false) Cookie userId,
HttpServletRequest request,HttpServletResponse response,#RequestBody UserBean entity
) throws IOException {
System.out.println("dsdsd");
System.out.print(userName);
response.setContentType( MediaType.APPLICATION_JSON_VALUE);
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "somethind wrong");
return null;
According to the Javadoc for the HttpServletReponse#sendError method:
Sends an error response to the client using the specified status. The
server defaults to creating the response to look like an
HTML-formatted server error page containing the specified message,
setting the content type to "text/html", leaving cookies and other
headers unmodified...
So sendError will generate an HTML error page using the message that you supplied and will override the content type to text/html.
Since the client end is expecting a JSON response, you may be better to manually set the response code and the message yourself using fields on your UserBean - assuming it can support it. That will then be serialized to a JSON response that your clientside Javascript can evaluate.
#RequestMapping(value = "{id}/{name}" ,method=RequestMethod.POST,produces = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody UserBean login(#PathVariable String id,#PathVariable("name") String userName,
#RequestHeader(value = "User-Agent") String user_agen,
#CookieValue(required = false) Cookie userId,
HttpServletRequest request,HttpServletResponse response,#RequestBody UserBean entity
) throws IOException {
System.out.println("dsdsd");
System.out.print(userName);
response.setContentType( MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
UserBean userBean = new UserBean();
userBean.setError("something wrong"); // For the message
return userBean;
There is also the option of using the Tomcat property org.apache.coyote. USE_CUSTOM_STATUS_MSG_IN_HEADER which will place the message into a custom response header. See this post and the Tomcat docs for more info.

Resources