servlet - Why is the XMLHttpRequest responseText always blank? - javascript

I am losing my mind trying to solve this problem over here. I have the following servlet deployed in Tomcat running on localhost:8080-:
#WebServlet(urlPatterns = { "/createcon" }, asyncSupported = true)
public class CreateCon extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* #see HttpServlet#HttpServlet()
*/
ConcurrentHashMap<String, AsyncContext> map;
public CreateCon() {
super();
// TODO Auto-generated constructor stub
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
public void init() {
map = new ConcurrentHashMap<>();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
AsyncContext context = request.startAsync(request,response);
context.setTimeout(10000);
if(!map.containsKey("Hello"))
map.put("Hello", context);
System.out.print("Inside GET");
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
AsyncContext context = map.get("Hello");
PrintWriter writer = context.getResponse().getWriter();
writer.write(request.getParameter("message"));
writer.flush();
System.out.print(request.getParameter("message"));
}
}
As you can see I am trying to store an AsyncContext that is created in Map. I code runs fine in Eclipse with Tomcat. As you can see above that I have added System.out.print to actually check whether the code is working properly or not. And it works exactly as expected.
But the problem is with the javascript below-:
function postMessage(){
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange=function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
alert(xmlhttp.responseText);
}
}
xmlhttp.open("POST", "/SampleTest/createcon", true);
xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
var messageText = escape(document.getElementById("i1").value);
document.getElementById("i1").value = "";
xmlhttp.send("message="+messageText);
}
The onreadystatechange fires exactly when expected but the xmlhttp.responseText is always blank.
I know that there is something known as a same-origin policy. But I don't understand why that's a problem here ? I am running everything on localhost:8080.
Why is this still happening and how do I solve this ?

Okay solved it. Guess it was my own silly mistake. The startchat() method should be modified like-:
function startChat() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "/SampleTest/createcon", true);
xmlhttp.send();
xmlhttp.onreadystatechange=function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
alert(xmlhttp.responseText);
}
}
}
Since I am trying to find the result from the request made at startChat().

Related

Sending Data from JS to servlet without using <form>

I am trying to get some dynamic buttons to send their id to my servlet. I think I am close but just cant figure out how to get the data on the backend.
HTML: (dynamically generated)
<button class="btn btn-success btn-reimb" id="${res[i][1].id}" onclick='approve(this)'><i class="fas fa-check"></i></button>
JS:
const approve = (e) => {
console.log(e.id);
const id = e.id;
var xhttp;
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState === 4 && this.status === 200) {
console.log("Sending...")
}
};
xhttp.open("POST", 'approve', true);
xhttp.send(id);
}
Servlet:
#WebServlet(name = "approve", urlPatterns = {"/approve"} )
public class ApproveServlet extends HttpServlet {
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
String id = req.getParameter("id");
System.out.println(id);
}
}
Thanks in advance!
EDIT:
Thanks to Nikos Paraskevopoulos! My servlet code now looks like:
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
ServletInputStream input = req.getInputStream();
StringBuilder string = new StringBuilder();
try (Reader reader = new BufferedReader(new InputStreamReader
(input, Charset.forName(StandardCharsets.UTF_8.name())))) {
int c = 0;
while ((c = reader.read()) != -1) {
string.append((char) c);
}
}
int id = Integer.parseInt(string.toString());
System.out.println(id);
The data you send with XMLHttpRequest is in the request body. Read it with req.getInputStream(). This gives you a ServletInputStream, which you can read as a standard InputStream.

Pass JSON Object through Jquery GET call to Java Servlet

how can i pass a JSON Array/Object with the JQUERY get Method to my Java Servlet?
So far , here's my code:
var json = {
MA_ID : $("#emplID").val(),
MA_Nachname : $("#nachname").val()
}
$.get(url + "/MA_Update", json)
[...]
MA_Update.java
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
StringBuffer jb = new StringBuffer();
String line = null;
BufferedReader reader = request.getReader();
while ((line = reader.readLine()) != null) {
jb.append(line);
}
try {
JSONObject jsonObject = HTTP.toJSONObject(jb.toString());
System.out.println(jsonObject);
} catch (JSONException e) {
// crash and burn
throw new IOException("Error parsing JSON request string");
}
}
But I only get
{"Request-URI":"","Method":"","HTTP-Version":""}
from my request
Do not use request.getReader(), use request.getParameter("MA_ID") etc., or request.getParameterMap() (and iterate over it).
The thing is, that $.get(url, jsObject) creates a HTTP GET request, where the fields of the jsObject are transformed into query parameters, i.e. http://your.server.com/MA_Update?MA_ID=someID&MA_Nachname=SomeLastName, so they are NOT available in the request body (as they would be in a POST request).

loading image without storing it to disk from a servlet with Jquery Asynchronously

I want to load an image from a servlet to a jsp file without storing it to any disk with help of jquery .It should be done Asynchronously . Below is my code
JSP.page ( Code of entire JSP page is not given ) . When the page is loaded GetCaptchaImage() function is called . This function will call doget method in the servlet Captcha. Image should be loaded in the result div. But nothing is been loaded . When I put an alert inside the javascript it shows data in encoded format .I have tried to encode the image in base64 format in servlet but still nothing comes to the browser. Even writing the response to printer object doesn't worked
data image link
<script src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
function GetCaptchaImage ()
{
$.get("Captcha",function(data){
$('.result').html('<img src="data:image/bmp;base64,' + data + '" />');
});
}
</script>
</head>
<body onload="GetCaptchaImage()">
<div class="result" >
</div>
Servlet code :
#WebServlet("/Captcha")
public class Captcha extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* #see HttpServlet#HttpServlet()
*/
public Captcha() {
super();
// TODO Auto-generated constructor stub
}
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
gtcResult = captcha.GenerateCaptchaCustom(100) // Generates the image
InputStream in = new ByteArrayInputStream(gtcResult.getbmp());
BufferedImage bImageFromConvert = ImageIO.read(in);
response.setContentType("image/bmp");
OutputStream out = response.getOutputStream();
ImageIO.write(bImageFromConvert, "bmp", out);
out.flush();
out.close();
}
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
System.out.println("duration : "+ duration);
}catch(Exception e){
System.out.println("Image Failed : "+ e.getMessage());
}
//response.getWriter().append("Served at: ").append(request.getContextPath());
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
}

HttpServletRequest can not get xhr request parameter

I am working with Spring and javascript. Calling #Controller with XhrHttpRequest Object.
I can see my parameter(JSON string) with Chrome Inspector, but when I call request.getParamter("id") returns null.
Calling part with js
function ajax(url, data, callback, method){
//data is {"id":"system", "password" : "1234"}
var httpRequest;
var afterAction = function(){
if(!httpRequest) {
console.error('can not find httpRequest variable');
return;
}
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) {
var responseData = httpRequest.responseText;
//alert(JSON.stringify(responseData));
console.log('Result of API call >>>', responseData);
if(typeof callback == 'function') {
callback(JSON.parse(responseData));
}
} else {
alert('There was a problem with the request.');
}
}
}
//=========== LOGIC ============
if (window.XMLHttpRequest) { // Mozilla, Safari, IE7+ ...
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE 6 and older
httpRequest = new ActiveXObject('Microsoft.XMLHTTP');
}
if(!method) method = 'POST';
data = (!!data) ? JSON.stringify(data) : '';
httpRequest.onreadystatechange = afterAction;
httpRequest.open(method.toUpperCase(), url, true);
httpRequest.setRequestHeader("Content-type", "application/json; charset=utf-8");
//httpRequest.setRequestHeader("Content-length", data.length);
//httpRequest.setRequestHeader("Connection", "close");
httpRequest.send(data);
}
receive part with Spring #Controller
#Controller
#RequestMapping(value={"member"}, produces={"application/json"})
#ResponseStatus(value = HttpStatus.OK)
public class MemberController {
/**
* #param request
* #param resp
* #return
* #throws Exception
*/
#RequestMapping(value={"/login"})
public #ResponseBody String login(HttpServletRequest request, HttpServletResponse resp) throws Exception {
System.out.println("Login request");
String id = String.valueOf(request.getParameter("id")); //returns null
String password = String.valueOf(request.getParameter("password")); //returns null
Map<String, String> result = new HashMap<String, String>();
result.put("result", "S");
result.put("message", "login success");
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(result);
}
}
I do not know why parameter becomes null. Thanks.
You need to follow the below steps to accept Json in your controller:
(1) Define UserLogin bean to hold the Json
public class UserLogin {
private String id;
private String password;
//Add getters and setters
}
(2) Change your controller to accept Json & receive the UserLogin bean
#Controller
#RequestMapping(value={"member"}, produces={"application/json"})
#ResponseStatus(value = HttpStatus.OK)
public class MemberController {
#RequestMapping(value={"/login"}, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public #ResponseBody String login(UserLogin userLogin) throws Exception {
System.out.println("Login request");
String id = userLogin.getId();
String password = userLogin.getPassword();
Map<String, String> result = new HashMap<String, String>();
result.put("result", "S");
result.put("message", "login success");
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(result);
}
}
This is an Alternative way with Jackson Library. I like #javaguy 's way, but using Jackson library could be more flexible so add this post.
Preparations
WebMvcConfigurerAdapter implements class or something equivalent with that
SpringFramework Environment. In my case, Eclipse Dynamic Web Project with Maven and spring-webmvc in pom.xml.
What I did...
Implement WebMvcConfigurerAdapter
Override Method configureMessageConverters
Change Controller parameters from HttpServeletRequest request, HttpServletResponse resp to #RequestBody Map<?, ?>.(You can change generic value. It does not matters for further process)
So Here's code.
ServerConfig.java (I block other Options to focus current issue)
#Configuration
#EnableWebMvc
#ComponentScan(basePackages={ ... }
, excludeFilters=#ComponentScan.Filter(Configuration.class))
//Filter 걸 때 Configuration.class 를 수동으로 등록해줘야 되는데 나은 방법 찾아보기
public class ServerConfig extends WebMvcConfigurerAdapter {
...
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter());
super.configureMessageConverters(converters);
}
};
And Controller (Change Parameter Types)
#Controller
#RequestMapping(value={"member"}, produces={"application/json"})
#ResponseStatus(value = HttpStatus.OK)
public class MemberApiController {
...
#RequestMapping(value={"/login"})
public #ResponseBody String login(#RequestBody Map<?, ?> jsonBody) throws JsonProcessingException {
System.out.println("Login request" + jsonBody.toString());
Map<String, String> result = new HashMap<String, String>();
String rs = "S";
String message = "SUCCESS";
System.out.println("ID >>> ", String.valueOf(jsonBody.get("id")));
System.out.println("PW >>> ", String.valueOf(jsonBody.get("password")));
result.put("result", rs);
result.put("result_msg", message);
mapper = new ObjectMapper();
return mapper.writeValueAsString(result);
}
};
However, since as far as I know #RequestBody does not have HttpSession, If you try to store data to HttpSession, you need another parameter HttpServletRequest.
I hope this could be a hand to others who has same problem with me :D

What is the "right" way to cache HTTP data between JavaScript and Java Servlets?

I am developing a client-server app with a JavaScript client and a Java Servlet running in Apache Tomcat. I am developing both ends, so I hope to do things the "right" way.
My JavaScript uses XMLHttpRequest. It seems like XMLHttpRequest does not do caching for me, so I used IndexedDB to cache responses. IndexDB is working sweetly for me in all the browsers I need to support (iOS, Android, PC, Mac).
I really want to manage cache validity with ETag values, so I tried this...
public class MyServlet_Etag extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String etag = myEtag(request);
String inm = request.getHeader("If-None-Match");
if (inm != null && inm.equals(etag))
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
else {
byte[] data = myData(request);
response.setHeader("ETag", etag);
response.getOutputStream().write(data);
response.setContentLength(data.length);
response.setContentType("application/octet-stream");
response.setStatus(HttpServletResponse.SC_OK);
}
}
}
... but Tomcat strips out my "ETag" headers. So I tried this...
public class MyServlet_LastModified extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
byte[] data = myData(request);
response.getOutputStream().write(data);
response.setContentLength(data.length);
response.setContentType("application/octet-stream");
response.setStatus(HttpServletResponse.SC_OK);
}
#Override
protected long getLastModified(HttpServletRequest request) {
return myLastModified(request);
}
}
The above Servlet code is simple, and in JavaScript I can manage my IndexedDB cache with the following code:
refreshURI = function(uri,lastModified,onRead) {
var req = new XMLHttpRequest();
req.open("GET", uri, true);
req.responseType = "arraybuffer";
req.setRequestHeader("If-Modified-Since", lastModified);
var _this = this;
req.onreadystatechange = function () {
if (req.readyState == 4) {
var hundred = Math.floor(req.status / 100);
if (hundred == 2) {
var response = req.response;
var lastModified = req.getResponseHeader("Last-Modified");
myIndexedDB.write(uri, req.response, lastModified);// Update our cache
onRead(response, lastModified);
} else if (hundred == 3) {
// No recent change, so skip further processing
}
}
};
};
So my app is working. But it can only handle 1 update per second, because the Last-Modified resolution is 1 second in HTTP's date format. I want to support many updates per second. I could use fake Last-Modified values that update by 1 second each update. But this is not the "right" way!
Q1. Is there some way to stop Tomcat stripping out my ETag values?
Q2. Is it acceptable to use fake Last-Modified HTTP header values between my JavaScript and my Servlet?
Q3. What is the right way to cache HTTP responses between a JavaScipt client and a Java Servlet?

Categories