Реально ли вызвать HTTP PUT с использованием прототипа? - PullRequest
0 голосов
/ 18 декабря 2010

Я бегу JEE6 с glassfish v3 на NetBean6.9 и работаю на RESTful web service.

У меня есть jsp-файл, который содержит функцию javascript ниже.

Он в основном читаетсяинформация из HTML input fields и преобразование в JSON format.

Затем с помощью onclick Ajax call, попытайтесь отправить строку JSON, используя метод HTTP PUT .(т.е. я пытаюсь UPDATE запись в БД с использованием REST) ​​

Для js framework я использую Prototype1.7

Когда я тестирую функцию ниже, она всегда возвращает 404таким образом, отображается сообщение «что-то пошло не так».

Согласно моему поиску, версия Prototype выше 1.5 поддерживает методы HTTP PUT / DELETE и для этого добавьте _method к URL-адресу запроса, например, что яя делаю:

var url = "/resources/inventory/" + invId + "?_method=PUT";

Это создаст, например:

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

Я посмотрел на Firebug и консоль, показывая, что запрос на самом деле POST .Не уверен, но я полагаю, что это из-за того, что Prototype использует туннелирование POST для достижения метода PUT?

Кроме того, несмотря на то, что вызывается Ajax, мой Java-файл с аннотированным JAX-RS с @POST даже не вызывается (@Версия GET работает с отдельными данными, так что это правильный файл), поскольку первая строка метода, в которой сообщение о спите не отображается, поэтому я подозреваю, что в моем операторе Ajax есть какая-то ошибка или что-то за пределами моего мышления ... может кто-нибудь дать мненамек?

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

Ответы [ 4 ]

1 голос
/ 03 мая 2013

Как вы уже упоминали в своем вопросе, прототип предотвращает PUT, DELETE, ... запросы по умолчанию. Некоторые люди (включая меня) думают, что это глупое поведение, но так как разработчик, похоже, не заботится об этом, мы должны сделать это, отредактировав саму функцию запроса (не затрагивая наш прототип. 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);
    }
};

Запустите этот код после запуска Prototype. Теперь это:

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

Будет вызывать фактический HTTP PUT Запрос ( см. JsFiddle ).

1 голос
/ 18 декабря 2010
0 голосов
/ 03 июня 2013

Я хочу поблагодарить RienNeVaPlus за его ответ. Я добавил дополнительное переопределение для корректной публикации с параметрами и типом содержимого:

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.

0 голосов
/ 20 декабря 2010

Ниже, который работает с использованием необработанного 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>
...