I want to do POST request to some API by netty. Request must contains parameters as form-data in body. How I try to do this:
FullHttpRequest httpRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, POST, url);
httpRequest.setUri("https://url.com/myurl");
ByteBuf byteBuf = Unpooled.copiedBuffer(myParameters, Charset.defaultCharset());
httpRequest.headers().set(ACCEPT_ENCODING, GZIP);
httpRequest.headers().set(CONTENT_TYPE, "application/json");
httpRequest.headers().set(CONTENT_LENGTH, byteBuf.readableBytes());
httpRequest.content().clear().writeBytes(byteBuf);
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, CNXN_TIMEOUT_MS)
.handler(new ChannelInitializerCustomImpl());
ChannelFuture cf = b.connect(url.getHost(), port);
cf.addListener(new ChannelFutureListenerCustomImpl();
That's worked ok, but result is different from I received by postman or other instruments.
What's the correct way to set my parameters as form-data to request body?
I solved this problem by using Apache httpcomponents library to create HtppEntity, serialize it to byte array and set to netty ByteBuf and also use jackson for parse json from String to Map:
Map<String, String> jsonMapParams = objectMapper.readValue(jsonStringParams, new TypeReference<Map<String, String>>() {});
List<NameValuePair> formParams = jsonMapParams.entrySet().stream()
.map(e -> new BasicNameValuePair(e.getKey(), e.getValue()))
.collect(Collectors.toList());
HttpEntity httpEntity = new UrlEncodedFormEntity(formParams);
ByteBuf byteBuf = Unpooled.copiedBuffer(EntityUtils.toByteArray(httpEntity));
httpRequest.headers().set(ACCEPT_ENCODING, GZIP);
httpRequest.headers().set(CONTENT_TYPE, "application/x-www-form-urlencoded");
httpRequest.headers().set(CONTENT_LENGTH, byteBuf.readableBytes());
httpRequest.content().clear().writeBytes(byteBuf);
I think that your request header is not set correct, to set content_type to "application/x-www-form-urlencoded" and have a try.
Related
I have below API which returns back the access_token.
POST https://idcs-xxxxxxxxxbf08128c3d93a19c.identity.c9dev2.oc9qadev.com/oauth2/v1/token
in header content-type is application/x-www-form-urlencoded. also in body it contains below parameter.
I send user name and password and it is secured with basic authentication. It provides access_token when I call from postman. also it provides output when I consume using HttpUrlConnection
url = new URL(tokenURL);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Authorization", auth);
connection.setRequestProperty("Accept", "application/json");
OutputStream os = connection.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
osw.write("grant_type=client_credentials&scope=" + scope);
The above code is working properly. But when I use jersey it gives 415 error. I am using below code.
String user="idcs-oda-zzzxxxxxf93560b94eb8a2e2a4c9aac9a3ff-t0_APPID";
String password="xxxxxxx-6f71-4af2-b5cc-9110890d1456";
String scope = "https://idcs-oda-xxxxxxxxxxxxxxxxe2a4c9aac9a3ff-t0.data.digitalassistant.oci.oc-test.com/api/v1";
String tokenURL = "https://idcs-xxxxxxxxxxxxxxxx28c3d93a19c.identity.c9dev2.oc9qadev.com/oauth2/v1/token";
HttpAuthenticationFeature feature= HttpAuthenticationFeature
.basicBuilder()
.nonPreemptive()
.credentials(user,password)
.build();
ClientConfig clientConfig = new ClientConfig();
clientConfig.register(feature);
Client client = ClientBuilder.newClient(clientConfig);
WebTarget webTarget= client.target(tokenURL);
PostDetails post= new PostDetails("client_credentials",scope); //Bean class to assign body parameter
Response response= webTarget.request()
.header("Content-Type", "application/x-www-form-urlencoded")
.post(Entity.json(post));
System.out.println(response);
Can somebody tell me what mistake I am doing in Response line.
You need to set your Accept on the request method:
Response response= webTarget.request(MediaType.APPLICATION_JSON)
.header("Content-Type", "application/x-www-form-urlencoded")
.post(Entity.json(post));
You also need to ensure that if your API accepts application/x-www-form-urlencoded content, that is what you are sending.
Currently, you are sending application/json content based on your usage of Entity.json(post).
I don't know what type is assigned to post, but you need to figure out how to convert it either to a Form or a MultiValuedMap<String,String>, and then use the form method on Entity to submit your content.
Response response= webTarget.request(MediaType.APPLICATION_JSON)
.header("Content-Type", "application/x-www-form-urlencoded")
.post(Entity.form(postForm)); //assuming postForm typed as Form or MultiValuedMap<String,String>
Taking a guess regarding post, creating postForm as a MultiValuedMap<String,String> may be as simple as the following (which you would place prior to your request, of course).
MultiValuedMap<String,String> postForm = new MultiValuedHashMap<>();
postForm.add("client_credentials",scope);
What you need is:
Response response= webTarget.request()
.accept("application/json") // Accept field from header of request
.header("Content-Type", "application/x-www-form-urlencoded") //manually set content-tyoe
.post(Entity.entity(input, MediaType.TEXT_PLAIN)); // request body
The best way to see what is Jersey actually is sending is to register logger, and log network. For example:
clientConfig.register(
new LoggingFeature(
new Slf4jLogger(this.getClass().getName(), null)));
where Slf4jLogger is from org.apache.cxf:cxf-core.
Dropwizard (Version 0.8.2) uses Jersey internally to provide HTTP client. I am using this client to send a Multipart POST request to an external Rest Endpoint to a SMS Service. Code is given below but it doesn't seems to be working because i am not receiving any message through this method also it does not throw any error.
URI for the first sample is http://enterprise.com/GatewayAPI/rest?userid=%s&password=%s&method=xlsUpload&filetype=zip&msg_type=TEXT&auth_scheme=PLAIN&v=1.1
FileDataBodyPart fileDataBodyPart = new FileDataBodyPart(fileName, file,
MediaType.APPLICATION_OCTET_STREAM_TYPE);
FormDataMultiPart multiPart = new FormDataMultiPart();
multiPart.field("fileName", fileName).bodyPart(fileDataBodyPart);
Entity<FormDataMultiPart> entity =
Entity.entity(multiPart, multiPart.getMediaType());// MediaType.MULTIPART_FORM_DATA_TYPE)
Client tenacityClient = TenacityJerseyClientBuilder
.builder(AppDependencyKeys.BULK_SMS)
.usingTimeoutPadding(Duration.milliseconds(500)).build(client)
.register(MultiPartFeature.class);
Invocation invocation = getResourceBuilder(tenacityClient, uri).buildPost(entity);
Future<Response> futureResponse = invocation.submit();
long start = System.currentTimeMillis();
futureResponse.get();
But the same works with below method when i use Apache Commons Httpclient. working code for the same is given below.
HttpClient client = new HttpClient();
PostMethod method = new
PostMethod("http://enterprise.com/GatewayAPI/rest");
Part[] parts = {
new StringPart("method", "xlsUpload"),
new StringPart("userid", "*******"),
new StringPart("password", "*******"),
new StringPart("filetype", "zip"),
new StringPart("v", "1.1"),
new StringPart("auth_scheme", "PLAIN"),
new FilePart(file.getName(), file)
};
method.setRequestEntity(new MultipartRequestEntity(parts, method.getParams()));
int statusCode = client.executeMethod(method);
log.info("Status code: {}", statusCode);
But i want to use the first way as that suits my infrastructure better.
I think you should set up properly media type for entity. Currently, you created new FormDataMultiPart but, you did not set and media type and it uses "text/plain" y default.
So, you should set up MediaType.APPLICATION_OCTET_STREAM_TYPE to your FormDataMultiPart as media type.
HttpRequest httpReq=new DefaultHttpRequest(HttpVersion.HTTP_1_1,HttpMethod.POST,uri);
httpReq.setHeader(HttpHeaders.Names.HOST,host);
httpReq.setHeader(HttpHeaders.Names.CONNECTION,HttpHeaders.Values.KEEP_ALIVE);
httpReq.setHeader(HttpHeaders.Names.ACCEPT_ENCODING,HttpHeaders.Values.GZIP);
String params="a=b&c=d";
ChannelBuffer cb=ChannelBuffers.copiedBuffer(params,Charset.defaultCharset());
httpReq.setHeader(HttpHeaders.Names.CONTENT_LENGTH,cb.readableBytes());
httpReq.setContent(cb);
Does not yield a valid request. What is the correct way to send a post request, preferably by constructing the parameters data manually as opposed to with the DataFactory. Also, why is HttpDataFactory not included in any of the releases?
You wrote everything correct, just add httpReq.setHeader(HttpHeaders.Names.CONTENT_TYPE,"application/x-www-form-urlencoded");
and your example will work. For more complex code you need to add url encoding.
DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, uri.toASCIIString());
request.headers().set(HttpHeaders.Names.HOST, ip);
request.headers().set(HttpHeaders.Names.CONTENT_TYPE,"application/x-www-form-urlencoded");
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
nvps.add(new BasicNameValuePair(param.getKey(), param.getValue()));
HttpEntity httpEntity = new UrlEncodedFormEntity(nvps);
ByteBuf byteBuf =
Unpooled.copiedBuffer(EntityUtils.toByteArray(httpEntity));
request.content().writeBytes(byteBuf);
request.headers().set(HttpHeaders.Names.CONTENT_LENGTH,request.content().readableBytes());
fu.channel().writeAndFlush(request)
I need to send a POST request to a web server which includes a gzipped request parameter. I'm using Apache HttpClient and I've read that it supports Gzip out of the box, but I can't find any examples of how to do what I need. I'd appreciate it if anyone could post some examples of this.
You need to turn that String into a gzipped byte[] or (temp) File first. Let's assume that it's not an extraordinary large String value so that a byte[] is safe enough for the available JVM memory:
String foo = "value";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (GZIPOutputStream gzos = new GZIPOutputStream(baos)) {
gzos.write(foo.getBytes("UTF-8"));
}
byte[] fooGzippedBytes = baos.toByteArray();
Then, you can send it as a multipart body using HttpClient as follows:
MultipartEntity entity = new MultipartEntity();
entity.addPart("foo", new InputStreamBody(new ByteArrayInputStream(fooGzippedBytes), "foo.txt"));
HttpPost post = new HttpPost("http://example.com/some");
post.setEntity(entity);
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(post);
// ...
Note that HttpClient 4.1 supports the new ByteArrayBody which can be used as follows:
entity.addPart("foo", new ByteArrayBody(fooGzippedBytes, "foo.txt"));
In a Java method, I'd like to use a Jersey client object to do a POST operation on a RESTful web service (also written using Jersey) but am not sure how to use the client to send the values that will be used as FormParam's on the server. I'm able to send query params just fine.
Not done this yet myself, but a quick bit of Google-Fu reveals a tech tip on blogs.oracle.com with examples of exactly what you ask for.
Example taken from the blog post:
MultivaluedMap formData = new MultivaluedMapImpl();
formData.add("name1", "val1");
formData.add("name2", "val2");
ClientResponse response = webResource
.type(MediaType.APPLICATION_FORM_URLENCODED_TYPE)
.post(ClientResponse.class, formData);
That any help?
Starting from Jersey 2.x, the MultivaluedMapImpl class is replaced by MultivaluedHashMap. You can use it to add form data and send it to the server:
WebTarget webTarget = client.target("http://www.example.com/some/resource");
MultivaluedMap<String, String> formData = new MultivaluedHashMap<String, String>();
formData.add("key1", "value1");
formData.add("key2", "value2");
Response response = webTarget.request().post(Entity.form(formData));
Note that the form entity is sent in the format of "application/x-www-form-urlencoded".
It is now the first example in the Jersey Client documentation
Example 5.1. POST request with form parameters
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:9998").path("resource");
Form form = new Form();
form.param("x", "foo");
form.param("y", "bar");
MyJAXBBean bean =
target.request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.entity(form,MediaType.APPLICATION_FORM_URLENCODED_TYPE),
MyJAXBBean.class);
If you need to do a file upload, you'll need to use MediaType.MULTIPART_FORM_DATA_TYPE.
Looks like MultivaluedMap cannot be used with that so here's a solution with FormDataMultiPart.
InputStream stream = getClass().getClassLoader().getResourceAsStream(fileNameToUpload);
FormDataMultiPart part = new FormDataMultiPart();
part.field("String_key", "String_value");
part.field("fileToUpload", stream, MediaType.TEXT_PLAIN_TYPE);
String response = WebResource.type(MediaType.MULTIPART_FORM_DATA_TYPE).post(String.class, part);
Simplest:
Form form = new Form();
form.add("id", "1");
form.add("name", "supercobra");
ClientResponse response = webResource
.type(MediaType.APPLICATION_FORM_URLENCODED_TYPE)
.post(ClientResponse.class, form);
Also you can try this:
MultivaluedMap formData = new MultivaluedMapImpl();
formData.add("name1", "val1");
formData.add("name2", "val2");
webResource.path("yourJerseysPathPost").queryParams(formData).post();