是否真的可以使用原型调用HTTP PUT

时间:2010-12-18 05:30:53

标签: java ajax rest prototypejs http-put

我正在JEE6glassfish v3 NetBean6.9正在RESTful web service上工作HTML input fields

我的jsp文件包含下面的javascript函数。

它基本上从JSON format读取信息并转换为onclick Ajax call

然后使用UPDATE尝试使用HTTP PUT方法发送JSON字符串。 (即我正在尝试使用REST Prototype1.7 db记录

对于我使用的js框架是var url = "/resources/inventory/" + invId + "?_method=PUT";

当我测试下面的功能时,它总是返回404,因此显示“出错”警报。

根据我的搜索,上面的1.5版本Prototype支持HTTP PUT / DELETE方法,并且这样做会将 _method 添加到请求URL,就像我正在做的那样:

http://localhost:8080/NoJSF/resources/inventory/123?_method=PUT

这将创建例如:

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

我查看了Firebug和控制台,显示该请求实际上是 POST 。不确定,但我相信这是因为Prototype使用POST隧道来实现PUT方法?

即使正在调用Ajax,我的带有JAX-RS注释的@JOST的Java文件甚至没有被调用(@GET版本正在使用单独的数据,所以这是正确的文件),因为它的方法的第一行吐出的消息没有出现所以我怀疑我的Ajax语句有一些bug或者有一些超出我思考的东西..有人能给我提示吗?

{{1}}

4 个答案:

答案 0 :(得分:1)

答案 1 :(得分:1)

正如您在问题中提到的那样,默认为prototype averts PUT, DELETE,... requestsSome people(包括我)认为这是愚蠢的行为,但由于开发人员似乎关心这一点,我们必须通过编辑请求函数本身来做到这一点(不要触及我们对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);
    }
};

在原型获得后运行此代码。 现在这个:

new Ajax.Request('42', {method:'PUT'});

会导致实际的 HTTP PUT 请求(see a jsFiddle)。

答案 2 :(得分:0)

使用原始xml而不是使用原型工作。

当我使用原型ajax调用时,不允许405方法返回,不确定原因。

<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>

答案 3 :(得分:0)

我要感谢RienNeVaPlus的回答。我添加了额外的覆盖,以便正确发布参数和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]);
        }
      };

仅测试了PUT方法。