In a Java HttpServlet, is it possible to request data from another local service using the original request's header information without necessarily forwarding?
For example, I have FooBar.java:
// Handles the url at /foo/bar and can be accessed at http://localhost/foo/bar
public class FooBar extends HttpServlet
{
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
Object data = ... // 1. Retrieve data at http://localhost/foo/baz utilizing the current request's header
Object newData = doSomething(data); // 2. Process the data
response.getWriter().write(newData.toString); // 3. Return the processed data
}
private Object doSomething(Object data)
{
// Perform some business logic
}
}
Step 1 is the issue here. The purpose of this is that I want to be able to perform some sort of logic on the data before returning it in full, but don't necessarily have access do make the changes on the handler at /foo/baz do to the propriety nature of things.
You can use this answer of me to create a HTTP Request: send get request
In addition, it may be necessary to copy the request header with some care:
private static final Set forbiddenCopyHeaders = new HashSet<>(Arrays.asList(new String[]{
"connection"
, "transfer-encoding"
, "content-length" // POST kann zu Status 500 führen, wenn die content-length kopiert wird
, "via"
, "x-forwarded-for"
, "x-forwarded-host"
, "x-forwarded-server"
}));
private void copyRequestHeaders(HttpServletRequest customerRequest, HttpRequestBase internRequest) throws
HttpException
{
Enumeration<String> headerNames = customerRequest.getHeaderNames();
String connectionHeader = customerRequest.getHeader("connection");
while (headerNames.hasMoreElements())
{
String headerName = headerNames.nextElement();
boolean copyAllowed = !forbiddenCopyHeaders.contains(headerName.toLowerCase()) &&
!StringUtils.containsIgnoreCase(connectionHeader, headerName);
if (copyAllowed)
{
Enumeration<String> values = customerRequest.getHeaders(headerName);
while (values.hasMoreElements())
{
internRequest.addHeader(headerName, values.nextElement());
}
}
}
setProxySpecificRequestHeaders(customerRequest, internRequest);
}
private void setProxySpecificRequestHeaders(HttpServletRequest customerRequest,
HttpRequestBase internRequest) throws HttpException
{
String serverHostName = "doorman";
try
{
serverHostName = InetAddress.getLocalHost().getHostName();
}
catch (UnknownHostException e)
{
logger.error("Couldn't get the hostname needed for headers x-forwarded-server and Via", e);
}
String originalVia = customerRequest.getHeader("via");
StringBuilder via = new StringBuilder("");
if (originalVia != null)
{
if (originalVia.contains(serverHostName))
{
logger.error("This proxy has already handled the Request, will abort.");
throw new HttpException("Request has a cyclic dependency on this proxy.");
}
else
{
via.append(originalVia).append(", ");
}
}
via.append(customerRequest.getProtocol()).append(" ").append(serverHostName);
internRequest.addHeader("via", via.toString());
internRequest.addHeader("x-forwarded-for", customerRequest.getRemoteAddr());
internRequest.addHeader("x-forwarded-host", customerRequest.getServerName());
internRequest.addHeader("x-forwarded-server", serverHostName);
internRequest.addHeader("accept-encoding", "");
}
Using HttpURLConnection and altering the header to include a property from the original request, I was able to get a BufferedReader from the HTTP request:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
// Step 1
String serverName = request.getLocalName();
String contextPath = request.getContextPath();
URL url = new URL("https://" + serverName + contextPath + "/baz");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Key Header", request.getHeader("Key Header"));
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
// Step 2
... // Do something with the data from the reader
// Step 3
... // Write the data back using the response
}
Related
I have a Java web application running under Apache Tomcat (8.0.21.0). Its function is to monitor various external processes and display alerts and periodic updated statuses in a browser. The main HTTP request handler is simple enough.
public class MyApplication extends HttpServlet
{
.
.
.
public void doPost (HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
processRequest (request, response);
}
public void doGet (HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
processRequest (request, response);
}
private static void processRequest (HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
String strOption = request.getParameter ("option");
int nOption = Integer.parseInt (strOption);
response.setContentType ("text/html");
PrintWriter out = response.getWriter ();
outputPage (out, nOption);
}
private void outputPage (PrintWriter out, int nOption)
{
out.println ("<!DOCTYPE html>");
out.println ("<html>");
out.println ("<head>");
switch (nOption)
{
// title, style and <body> content depend on option passed in request
.
.
.
}
out.println ("</body>);
out.println ("</html>");
}
}
However, the application also includes a TCP Listener and socket, to receive IoT (Internet of Things) messages:
public class MyTCPconnection extends Thread
{
public Socket clientSocket; // socket created by listener
private String url = "[local host address and servlet name]";
.
.
.
public void run ()
{
int RC = 400; // default value = "Bad Request"
try
{
// get bytes from remote process
int receiveBufferSize = clientSocket.getReceiveBufferSize ();
byte[] receiveBuffer = new byte[receiveBufferSize];
int bytesRead = TCPreceive (clientSocket, receiveBuffer); // not shown
if (bytesRead != -1 && bytesRead != 0)
{
String strOption = getOption (receiveBuffer); // not shown
}
HttpPost httpPost = new HttpPost (url);
httpPost.setHeader ("Accept", "text/html,application/xhtml+xml,application/xml");
httpPost.setHeader ("Content-Type", "application/x-www-form-urlencoded");
List<NameValuePair> requestParams = new ArrayList<NameValuePair>();
reqestParams.add (new BasicNameValuePair ("option", value));
CloseableHttpClient httpClient = HttpClients.createDefault ();
CloseableHttpResponse response = httpClient.execute (httpPost);
RC = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString (response.getEntity ());
system.out.println (responseBody);
}
catch (UnknownHostException e)
{
RC = 404;
}
catch (IOException e)
{
RC = 400;
}
TCPsend (clientSocket, RC); // reply to remote process, not shown
}
}
Take for granted that MyTCPconnection.run () generates a valid HTTP request body and submits a POST request to the main application. The problem I have encountered is that, where the POST is made from a web browser (IExplorer, Firefox etc), the application outputs a web page in the browser, but on receiving the POST request from the internal MyTCPconnection instance, it outputs nothing to any browser. Instead, it redirects the entire output to the responseBody.
I thought at first that I merely needed to save the HttpServletResponse and PrintWriter variables from a request from the browser, and pass the saved PrintWriter instance to the function outputPage. However, when I logged these, the results were:
Request from browser:
HttpServletResponse response = org.apache.catalina.connector.ResponseFacade#3e1d266b
PrintWriter out = org.apache.catalina.connector.CoyoteWriter#6bc55aa8
Request from MyTCPconnection.run ():
HttpServletResponse response = org.apache.catalina.connector.ResponseFacade#3e1d266b
PrintWriter out = org.apache.catalina.connector.CoyoteWriter#6bc55aa8
Any hints or hlp would be appreciated
I want to do a form POST request to the url,in case of valid response callback URL should be called(or hit) else should be redirected to another page of the same application.
Eg : While doing online payment, when we click on pay on any site,it is redirected to our mentioned url,if the user ain't logged in, user is redirected to login page.
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Error error = null;
String jNo=request.getParameter("jNo");
String emailId=request.getParameter("emailId");
String mobileNo=request.getParameter("mobileNo");
String callBackUrl=request.getParameter("url");
HttpResponse httpRespnse=null;
try {
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target("https://localhost:8080/abc/xyz.aspx");
Invocation.Builder builder1 = webTarget.request(MediaType.APPLICATION_FORM_URLENCODED);
Form form = new Form();
form.param("jNo", jNo);
form.param("emailId", emailId);
form.param("url", callBackUrl);
form.param("mobileNo", mobileNo");
Response response1 = null;
response1 = builder1.post(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED));
String responseXml = response1.readEntity(String.class);
//PrintWriter out=new PrintWriter();
System.out.println(response1.getStatus());
} catch (Exception e) {
logger.error("Issue in Request" + e);
System.out.println(e.getMessage());
e.printStackTrace();
error = aadharProcess.getErrorMsg(Constants.ERR_CODE_INTERNAL_ERROR);
}
}
I have problem when I submit my form to insert data
the URL can't change and when I refresh it, the data reinsert
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String _1 = request.getParameter("company_name").toString();
String _2 = request.getParameter("city").toString();
String _3 = request.getParameter("state").toString();
String _4 = request.getParameter("zipcode").toString();
String _5 = request.getParameter("branch").toString();
String _6 = request.getParameter("address").toString();
Database db = (Database) getServletContext().getAttribute("db");
try {
String sql = "insert into company(company_name,city,state,zipcode,branch,company_address) values('"+_1+"','"+_2+"','"+_3+"','"+_4+"','"+_5+"','"+_6+"')";
db.updateSql(sql);
} catch (Exception e2) {
System.out.println(e2);
}
getServletContext().getRequestDispatcher("/company.jsp").forward(request, response);
}
Your problem comes from the understanding of the forward method.
This method transfer the request and the response object to the new URL. It is invisible for the client's browser so the URL is unchanged. By reloading the page, you repeat your resquest so your sending again your data.
This behaviour is completely normal. If you want to redirect to another URL and have another request then you should use the sendRedirect method.
Refer to this post to have a complete description of both methods.
Hi I am getting the access_token value dynamically from server for servlet request it is below: now i want to retrive the access_taken value in to my servlet program.
{
"access_token":"AQWP_EVkqdc7E0wD09J6msmjnUlvilhP304gUIDzl6KKgNxwnHyz_W9nOxS0IroDJwEfVr3n3O-IC9YKc3bjyuwYRm6qbKRiP3A2AzuDjo8ohZERZFRCMyfjjqqDjNJ5J5ReCQDhkFJam51eiqsOeXDg4U_c9XJzc1dUx7Qxck0p9RNE0",
"expires_in": 5183999
}
my code is below:
public class Demo extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final String PROTECTED_RESOURCE_URL = "http://api.linkedin.com/v1/people/~:(first-name,last-name,email-address)";
/**
* #see HttpServlet#HttpServlet()
*/
public Demo() {
super();
// TODO Auto-generated constructor stub
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
PrintWriter out=response.getWriter();
String authCode = request.getParameter("code");
request.setAttribute("authCode",authCode);
out.println(authCode);
doPost(request,response);
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
PrintWriter out=response.getWriter();
Object url=request.getAttribute("authCode");
response.sendRedirect("https://www.linkedin.com/uas/oauth2/accessToken?grant_type=authorization_code&code="+url+"&redirect_uri=http://localhost:8080/LinkedinMails/dem&client_id=xxxxxxxxxxxxx&client_secret=xxxxxxxxxxxxxxx");
}
}
Thank You.
public String doGet(String url) throws Exception {
URL urlObj = new URL(url);
HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();
conn.setDoOutput(true);
String line;
StringBuffer buffer = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(
conn.getInputStream()));
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
reader.close();
conn.disconnect();
return buffer.toString();
}
Now you can call this method from your servlet to get server response in servlet. Hope it will useful to you.
You can use Gson or Jackson libraries for conveting your JSON response.
Using Jackson:
new ObjectMapper().readValue(result, LinkedIn.class);
where result is your JSON that contains access_Token and expires_in
LinkedIn.java
#JsonIgnoreProperties(ignoreUnknown=true)
public class LinkedIn
{
#JsonProperty("access_token")
private String accessToken;
#JsonProperty("expires_in")
private long expiresIn;
// Getters and setters for expiresOn and accessToken
}
In your Servlet/Controller
LinkedIn l= new ObjectMapper().readValue(result, LinkedIn.class); // Result is your JSON response which has access token and expires from LinkedIn
l.getAccessToken() ; // Returns you access token
l.getExpiresIn() // Returns you the expires time frame
}
Using JSONObject
String s="{\n" +
" \"access_token\":\"AQWP_EVkqdc7E0wD09J6msmjnUlvilhP304gUIDzl6KKgNxwnHyz_W9nOxS0IroDJwEfVr3n3O-IC9YKc3bjyuwYRm6qbKRiP3A2AzuDjo8ohZERZFRCMyfjjqqDjNJ5J5ReCQDhkFJam51eiqsOeXDg4U_c9XJzc1dUx7Qxck0p9RNE0\",\n" +
" \"expires_in\": 5183999\n" +
"}"; // This contains your access token JSON
JSONParser parser = new JSONParser();
JSONObject o = (JSONObject) parser.parse(s);
System.out.println("Access Token: "+o.get("access_token")); //returns your access token
System.out.println("Expires: "+o.get("expires_in"));
Getting the Access Token JSON:
In your Demo Servlet, doPost method, instead of sendRedirect do a
http Post (Using Apache Http Client or java.net)call to the url.
Once the HTTP Post is done, You get back a Http response which will be application/json content. So get this String content (which contains application/json). This string content is your access_token sent to you by LinkedIn. Once you get back the response, do this:
JSONParser parser = new JSONParser();
JSONObject o = (JSONObject) parser.parse(responseString); // responseString is the JSON that you got from LinkedIn.
System.out.println("Access Token: "+o.get("access_token")); //returns your access token
System.out.println("Expires: "+o.get("expires_in"));
I have several servlets, which
take JSON-encoded requests as inputs,
process them and
return responses to the client as JSON-encoded objects.
Up to now I used Android as client (sample Android code see below).
Now I want to write a plain old Java program, which would send requests and receive the responses (do the same as the Android code). For this purpose I wrote a Java test (code see below, section Java code) and ran it.
At the client side I get this error:
21:43:38.930 [main] ERROR r.a.c.t.TestAcceptanceProcedure1 -
java.io.IOException: Server returned HTTP response code: 405 for URL: http://myserver/myapp/rest/GetUserIdService
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1441) ~[na:1.6.0_23]
at testclient.TestAcceptanceProcedure1.test(TestAcceptanceProcedure1.java:47) ~[test-classes/:na]
In the server log, I see this message:
WARNING: No operation matching request path "/myapp/rest/GetUserIdService" is found, Relative Path: /, HTTP Method: GET, ContentType: */*, Accept: text/html,image/gif,image/jpeg,*/*,*/*;q=.2,. Please enable FINE/TRACE log level for more details
Question: How should I change my Java test to fix this error?
Note that the server is up and running (when I execute the Android code, it works).
Android code:
Sending the request and receiving the response:
final GetSimulationStatusRequest request = new GetSimulationStatusRequest();
final String json = Utils.convertToJson(request, getClass());
final String serverUrl = Utils.getServerUrl(this, "GetSimulationStatusService");
final IGetSimulationStatusAsyncTask getSimulationStatusTask =
asyncTaskFactory.createGetSimulationStatusAsyncTask(getWebServiceHelper());
Utils.setRequestAndServerUrl(json, serverUrl, getSimulationStatusTask);
final GetSimulationStatusResponse simulationStatusReponse =
getSimulationStatusTask.get();
Utils.convertToJson:
public static String convertToJson(final Object aRequest, Class<? extends Activity> aClass) {
final ObjectMapper mapper = new ObjectMapper();
String json = null;
try {
json = mapper.writeValueAsString(aRequest);
} catch (final JsonProcessingException exception) {
Log.e(aClass.getSimpleName(), exception.getLocalizedMessage(),
exception);
}
return json;
}
Utils.setRequestAndServerUrl:
public static void setRequestAndServerUrl(final String aJson,
final String aServerUrl, final IAsyncTask aTask) {
aTask.addNameValuePair("request", aJson);
aTask.sendRequest(new String[] { aServerUrl });
}
GetSimulationStatusAsyncTask:
public class GetSimulationStatusAsyncTask
extends AsyncTask<String, String, GetSimulationStatusResponse>
implements IGetSimulationStatusAsyncTask {
private static final String TAG = GetSimulationStatusAsyncTask.class.getSimpleName();
private IWebServiceTaskHelper helper;
private ICcpResponseParser<GetSimulationStatusResponse> responseParser =
new CcpResponseParser<GetSimulationStatusResponse>();
public GetSimulationStatusAsyncTask(final IWebServiceTaskHelper aHelper) {
helper = aHelper;
}
#Override
public void addNameValuePair(final String aName, final String aValue) {
helper.addNameValuePair(aName, aValue);
}
#Override
protected GetSimulationStatusResponse doInBackground(String... aArgs) {
return (GetSimulationStatusResponse)Utils.processResponse(this.helper, TAG, responseParser,
GetSimulationStatusResponse.class, aArgs);
}
#Override
public void sendRequest(final String[] aArgs) {
execute(aArgs);
}
}
Java code:
#Test
public void test() throws JsonProcessingException, MalformedURLException {
final GetUserIdRequest request = new GetUserIdRequest();
request.setDeviceId("PC1");
final String requestAsString = convertToJson(request);
final String serverUrl = getServerUrl("GetUserIdService");
final URL url = new URL(serverUrl);
HttpURLConnection connection = null;
InputStream inputStream = null;
try {
connection = (HttpURLConnection) url.openConnection();
connection.addRequestProperty("request", requestAsString);
connection.connect();
inputStream = connection.getInputStream();
final String responseAsString = IOUtils.toString(inputStream);
LOGGER.debug("responseAsString: " + responseAsString);
} catch (final IOException exception) {
LOGGER.error("", exception);
}
finally
{
IOUtils.closeQuietly(inputStream);
}
}
private String convertToJson(final GetUserIdRequest aRequest) throws JsonProcessingException {
final ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(aRequest);
}
private String getServerUrl(final String aServiceName)
{
return "http://myserver.com/myapp/rest/" + aServiceName;
}
Update 1 (09.10.2013 12:23 MSK):
#Path("/GetSimulationStatusService")
public class GetSimulationStatusService extends BaseCcpService {
private GetSimulationStatusRequestParser requestParser =
new GetSimulationStatusRequestParser();
#POST
#Produces("text/plain")
public String getSimulationStatus(#FormParam("request") final String aRequestJson)
throws JsonProcessingException
{
final GetSimulationStatusRequest request = requestParser.convert(aRequestJson);
final GetSimulationStatusResponse response = new GetSimulationStatusResponse();
response.setRequestId(request.getId());
response.setCycle(getPersistence().getCurrentCycle(request.getUserId()));
response.setLabourForce(getPersistence().getLabourForceSimulationParameter(
request.getUserId()));
return getObjectMapper().writeValueAsString(response);
}
}
Update 2 (09.10.2013 20:48 MSK): When I change the code like shown below, I get 500 HTTP response. At the server side, the aRequest argument of the method GetUserIdService.getUserId is null.
connection = (HttpURLConnection) url.openConnection();
connection.addRequestProperty("request", requestAsString);
connection.setRequestMethod("POST"); // Added this line
connection.connect();
Update 3 (09.10.2013 23:15): This one works:
#Test
public void test() throws JsonProcessingException, MalformedURLException
{
final GetUserIdRequest request = new GetUserIdRequest();
request.setDeviceId("PC1");
final String requestAsString = convertToJson(request);
final String serverUrl = getServerUrl("GetUserIdService");
final URL url = new URL(serverUrl);
HttpURLConnection connection = null;
InputStream inputStream = null;
OutputStream outputStream = null;
try {
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.connect();
outputStream = connection.getOutputStream();
IOUtils.write("request=" + requestAsString, outputStream);
inputStream = connection.getInputStream();
final String responseAsString = IOUtils.toString(inputStream);
LOGGER.debug("responseAsString: " + responseAsString);
} catch (final IOException exception) {
LOGGER.error("", exception);
}
finally
{
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(outputStream);
}
}
The 405 HTTP error code means that given method (GET) is not supported by the endpoint. Probably instead of GET request you want to send POST. I don't know what kind of request is sent by Android client.
Do you have endpoint specification/documentation?
Here you'll find information how to invoke POST using plain Java API. If you can use external libraries in your test then it can be achieved a lot easier using RESTEasy.