I'm running JEE6
with glassfish v3
on NetBean6.9
and working on RESTful web service
.
I have jsp file which contains javascript function below.
It basically read info from HTML input fields
and convert to JSON format
.
Then with onclick Ajax call
, attempt to send JSON string using HTTP PUT method.
(i.e. I'm trying to UPDATE
the db record using REST)
For js framework I'm using is Prototype1.7
When I test the function below, it always return 404 thus "something went wrong" alert is displayed.
According to my search Prototype above 1.5 version supports HTTP PUT/DELETE methods and to do so add _method to the request URL like what I'm doing:
var url = "/resources/inventory/" + invId + "?_method=PUT";
This will create for instance:
http://localhost:8080/NoJSF/resourc开发者_开发问答es/inventory/123?_method=PUT
I looked at Firebug and console showing that the request is actually POST. Not sure but I believe this is because of Prototype using POST tunneling to achieve PUT method?
Also even though Ajax is being called, my Java file with JAX-RS annotated witn @POST is not even being called (@GET version is working with separate data so this is the right file) since the first line of its method that spit message is not showing up so I suspect my Ajax statement has some bug or there is something beyond my thinking.. could anyone give me hint?
function protoAjaxPut() {
//get all fields value and store into json
var invId = document.getElementById("invIdField").value;
var invName = document.getElementById("invNameField").value;
//put info into JSON format
var jsonInput = JSON.stringify(new Array(invName));
var url = "/resources/inventory/" + invId + "?_method=PUT";
new Ajax.Request(url, {
method:'put',
postBody: jsonInput,
ContentType: 'application/json',
onSuccess: function(transport) {
var responseData = transport.responseText;
document.getElementById('putResponseText').innerHTML = responseData;
},
onFailure: function() { alert('something went wrong!')}
})
}//end protoAjaxPut
They are tunneled:
http://dobrzanski.net/2007/04/22/using-put-and-delete-methods-in-ajax-requesta-with-prototypejs/
As you already mentioned in your question, prototype averts PUT, DELETE,... requests by default. Some people (including me) think that this is stupid behavour, but since the developer doenst seem to care about that, we have to do it by editing the request-function itself (without touching our dist of prototype.js!):
Ajax.Request.prototype.request = function(url) {
this.url = url;
this.method = this.options.method;
var params = Object.isString(this.options.parameters) ?
this.options.parameters :
Object.toQueryString(this.options.parameters);
// NOTE: THE MISSING PART WAS HERE
if (params && this.method === 'get') {
// when GET, append parameters to URL
this.url += (this.url.include('?') ? '&' : '?') + params;
}
this.parameters = params.toQueryParams();
try {
var response = new Ajax.Response(this);
if (this.options.onCreate) this.options.onCreate(response);
Ajax.Responders.dispatch('onCreate', this, response);
this.transport.open(this.method.toUpperCase(), this.url,
this.options.asynchronous);
if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1);
this.transport.onreadystatechange = this.onStateChange.bind(this);
this.setRequestHeaders();
this.body = this.method == 'post' ? (this.options.postBody || params) : null;
this.transport.send(this.body);
/* Force Firefox to handle ready state 4 for synchronous requests */
if (!this.options.asynchronous && this.transport.overrideMimeType)
this.onStateChange();
}
catch (e) {
this.dispatchException(e);
}
};
Run this code after Prototype got inited. Now this:
new Ajax.Request('42', {method:'PUT'});
Will cause an actual HTTP PUT Request (see a jsFiddle).
Below which using raw xml rather than using prototype works.
When I use prototype ajax call, 405 method not allowed would return, not sure why.
<script type="text/javascript">
function simplePut() {
var xmlHttp = new XMLHttpRequest();
var invId = document.getElementById("invIdField").value;
var invName = document.getElementById("invNameField").value;
//put info into JSON format
var jsonInput = JSON.stringify(new Array(invId, invName));
var url = "resources/inventory/" + invId;
xmlHttp.onreadystatechange = function() {
if(xmlHttp.readyState == 4 && xmlHttp.status == 200) {
//out = xmlHttp.responseText;
document.getElementById('simple').innerHTML = xmlHttp.responseText;
}
}
xmlHttp.open("put", url, true);
//xmlHttp.open("put", "resources/inventory/1", true);
//xmlHttp.setRequestHeader("Content-Type", "text/plain");
xmlHttp.setRequestHeader("Content-Type", "application/json");
xmlHttp.send(jsonInput);
}//end protoAjaxPut
</script>
...html body
<body>
<h1>Inventory page</h1>
<table border="1" cellspacing="1" cellpadding="5">
<th>id</th>
<th>amount</th>
<c:forEach items="${inventoryList}" var="inv" >
<tr>
<td>${inv.id}</td>
<td><a href="" onclick="ajaxGet(${inv.id}); return false;">${inv.amount}</a></td>
</tr>
</c:forEach>
</table>
<hr />
<h3>REST</h3>
<form method="post" action="">
Inventory ID: <input type="test" id="invIdField" readonly /><br />
Inventory Name: <input type="text" id="invNameField" /><br />
<input type="button" value="insert POST form" onclick="protoAjaxPost()" /><br />
<!-- <input type="button" value="update PUT" onclick="protoAjaxPut()" /><br /> -->
<div id="putResponseText"></div>
</form>
<button onclick="protoAjaxPut()">update PUT</button><br />
<button onclick="simplePut()">call SIMPLE PUT</button><br />
<button onclick="ajaxDelete()">HTTP DELETE</button><br />
<div id="simple"></div>
</body>
I want to thank RienNeVaPlus for his answer. I added additional override in order to post correctly with parameters and contenttype:
Ajax.Request.prototype.setRequestHeaders = function() {
var headers = {
'X-Requested-With': 'XMLHttpRequest',
'X-Prototype-Version': Prototype.Version,
'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
};
if (this.method == 'post' || this.method=='put') {
headers['Content-type'] = this.options.contentType +
(this.options.encoding ? '; charset=' + this.options.encoding : '');
/* Force "Connection: close" for older Mozilla browsers to work
* around a bug where XMLHttpRequest sends an incorrect
* Content-length header. See Mozilla Bugzilla #246651.
*/
if (this.transport.overrideMimeType &&
(navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
headers['Connection'] = 'close';
}
if (typeof this.options.requestHeaders == 'object') {
var extras = this.options.requestHeaders;
if (Object.isFunction(extras.push))
for (var i = 0, length = extras.length; i < length; i += 2)
headers[extras[i]] = extras[i+1];
else
$H(extras).each(function(pair) { headers[pair.key] = pair.value });
}
for (var name in headers) {
this.transport.setRequestHeader(name, headers[name]);
}
};
Only tested for PUT method.
精彩评论