Чистый JavaScript: отправка данных POST без формы

141

Есть ли способ отправить данные с помощью метода POST без формы и без обновления страницы, используя только чистый JavaScript (не jQuery $.post())? Может быть httprequestили что-то еще (просто не могу найти сейчас)?

Джон
источник
1
XMLHttpRequest - это ответ ... $. Post использует то же самое под капотом.
Chandu
Этот вопрос может вам помочь: [ stackoverflow.com/questions/58217910/… [1]: stackoverflow.com/questions/58217910/…
Хорхе дель Кампо Андраде

Ответы:

140

Вы можете отправить его и вставить данные в тело:

var xhr = new XMLHttpRequest();
xhr.open("POST", yourUrl, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
    value: value
}));

Кстати, для запроса на получение:

var xhr = new XMLHttpRequest();
// we defined the xhr

xhr.onreadystatechange = function () {
    if (this.readyState != 4) return;

    if (this.status == 200) {
        var data = JSON.parse(this.responseText);

        // we get the returned data
    }

    // end of state change: it can be after some time (async)
};

xhr.open('GET', yourUrl, true);
xhr.send();
Джон Джи
источник
2
Для чего нужна настоящая логическая переменная в xhr.open?
Hylle
68

[Новый на момент написания в 2017 году] Fetch API предназначен для упрощения запросов GET, но он также может выполнять POST.

let data = {element: "barium"};

fetch("/post/data/here", {
  method: "POST", 
  body: JSON.stringify(data)
}).then(res => {
  console.log("Request complete! response:", res);
});

Если вы такой же ленивый, как я (или просто предпочитаете ярлык / помощник):

window.post = function(url, data) {
  return fetch(url, {method: "POST", body: JSON.stringify(data)});
}

// ...

post("post/data/here", {element: "osmium"});
ContinuousLoad
источник
54

Вы можете использовать XMLHttpRequestобъект следующим образом:

xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
xhr.send(someStuff);

Этот код будет отправлен someStuffв url. Просто убедитесь, что когда вы создаете свой XMLHttpRequestобъект, он будет кроссбраузерным. Есть бесконечное количество примеров того, как это сделать.

Джеймс Аллардис
источник
1
не могли бы вы написать пример someStuff?
FluorescentGreen5
4
someStuff = 'param1 = val1 & param2 = val2 & param3 = val3'
Camel
1
Это хороший ответ, и это someStuffможет быть что угодно, даже простая строка. вы можете проверить запрос с помощью онлайн-сервисов, таких как мой личный фаворит: ( requestb.in )
JamesC
application/x-www-form-urlencodedтип MIME не имеет charsetпараметр: iana.org/assignments/media-types/application/...
JBG
29

Кроме того , RESTful позволяет получить данные обратно из POST запроса.

JS (поместите в static / hello.html для обслуживания через Python):

<html><head><meta charset="utf-8"/></head><body>
Hello.

<script>

var xhr = new XMLHttpRequest();
xhr.open("POST", "/postman", true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
    value: 'value'
}));
xhr.onload = function() {
  console.log("HELLO")
  console.log(this.responseText);
  var data = JSON.parse(this.responseText);
  console.log(data);
}

</script></body></html>

Сервер Python (для тестирования):

import time, threading, socket, SocketServer, BaseHTTPServer
import os, traceback, sys, json


log_lock           = threading.Lock()
log_next_thread_id = 0

# Local log functiondef


def Log(module, msg):
    with log_lock:
        thread = threading.current_thread().__name__
        msg    = "%s %s: %s" % (module, thread, msg)
        sys.stderr.write(msg + '\n')

def Log_Traceback():
    t   = traceback.format_exc().strip('\n').split('\n')
    if ', in ' in t[-3]:
        t[-3] = t[-3].replace(', in','\n***\n***  In') + '(...):'
        t[-2] += '\n***'
    err = '\n***  '.join(t[-3:]).replace('"','').replace(' File ', '')
    err = err.replace(', line',':')
    Log("Traceback", '\n'.join(t[:-3]) + '\n\n\n***\n*** ' + err + '\n***\n\n')

    os._exit(4)

def Set_Thread_Label(s):
    global log_next_thread_id
    with log_lock:
        threading.current_thread().__name__ = "%d%s" \
            % (log_next_thread_id, s)
        log_next_thread_id += 1


class Handler(BaseHTTPServer.BaseHTTPRequestHandler):

    def do_GET(self):
        Set_Thread_Label(self.path + "[get]")
        try:
            Log("HTTP", "PATH='%s'" % self.path)
            with open('static' + self.path) as f:
                data = f.read()
            Log("Static", "DATA='%s'" % data)
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.end_headers()
            self.wfile.write(data)
        except:
            Log_Traceback()

    def do_POST(self):
        Set_Thread_Label(self.path + "[post]")
        try:
            length = int(self.headers.getheader('content-length'))
            req   = self.rfile.read(length)
            Log("HTTP", "PATH='%s'" % self.path)
            Log("URL", "request data = %s" % req)
            req = json.loads(req)
            response = {'req': req}
            response = json.dumps(response)
            Log("URL", "response data = %s" % response)
            self.send_response(200)
            self.send_header("Content-type", "application/json")
            self.send_header("content-length", str(len(response)))
            self.end_headers()
            self.wfile.write(response)
        except:
            Log_Traceback()


# Create ONE socket.
addr = ('', 8000)
sock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(addr)
sock.listen(5)

# Launch 100 listener threads.
class Thread(threading.Thread):
    def __init__(self, i):
        threading.Thread.__init__(self)
        self.i = i
        self.daemon = True
        self.start()
    def run(self):
        httpd = BaseHTTPServer.HTTPServer(addr, Handler, False)

        # Prevent the HTTP server from re-binding every handler.
        # https://stackoverflow.com/questions/46210672/
        httpd.socket = sock
        httpd.server_bind = self.server_close = lambda self: None

        httpd.serve_forever()
[Thread(i) for i in range(10)]
time.sleep(9e9)

Журнал консоли (хром):

HELLO
hello.html:14 {"req": {"value": "value"}}
hello.html:16 
{req: {…}}
req
:
{value: "value"}
__proto__
:
Object

Журнал консоли (firefox):

GET 
http://XXXXX:8000/hello.html [HTTP/1.0 200 OK 0ms]
POST 
XHR 
http://XXXXX:8000/postman [HTTP/1.0 200 OK 0ms]
HELLO hello.html:13:3
{"req": {"value": "value"}} hello.html:14:3
Object { req: Object }

Журнал консоли (Edge):

HTML1300: Navigation occurred.
hello.html
HTML1527: DOCTYPE expected. Consider adding a valid HTML5 doctype: "<!DOCTYPE html>".
hello.html (1,1)
Current window: XXXXX/hello.html
HELLO
hello.html (13,3)
{"req": {"value": "value"}}
hello.html (14,3)
[object Object]
hello.html (16,3)
   {
      [functions]: ,
      __proto__: { },
      req: {
         [functions]: ,
         __proto__: { },
         value: "value"
      }
   }

Журнал Python:

HTTP 8/postman[post]: PATH='/postman'
URL 8/postman[post]: request data = {"value":"value"}
URL 8/postman[post]: response data = {"req": {"value": "value"}}
personal_cloud
источник
8

Существует простой способ обернуть ваши данные и отправить их на сервер, как если бы вы отправляли HTML-форму, используя POST. вы можете сделать это с помощью FormDataобъекта следующим образом:

data = new FormData()
data.set('Foo',1)
data.set('Bar','boo')

let request = new XMLHttpRequest();
request.open("POST", 'some_url/', true);
request.send(data)

теперь вы можете обрабатывать данные на стороне сервера точно так же, как вы работаете с регулярными HTML-формами.

Дополнительная информация

Рекомендуется не устанавливать заголовок Content-Type при отправке FormData, так как браузер позаботится об этом.

Армин Хемати Ник
источник
❗️ FormDataсоздаст многостраничный запрос формы, а не application/x-www-form-urlencodedзапрос
ccpizza
@ccpizza - спасибо за разъяснения. поскольку OP не упомянул, какой тип данных должен быть опубликован, я думаю, что FormData является наиболее подходящим способом ответа.
Армин Хемати Ник
7

navigator.sendBeacon ()

Если вам просто нужны POSTданные и не требуется ответа от сервера, самым коротким решением будет использование navigator.sendBeacon():

const data = JSON.stringify({
  example_1: 123,
  example_2: 'Hello, world!',
});

navigator.sendBeacon('example.php', data);
Грант Миллер
источник
1
Не удалось выполнить sendBeacon в Navigator: маяки поддерживаются только через HTTP (S).
Ali80
navigator.sendBeaconна мой взгляд, не предназначен для использования с этой целью.
jolivier
6

Вы можете использовать XMLHttpRequest, fetch API, ...

Если вы хотите использовать XMLHttpRequest, вы можете сделать следующее

var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
    name: "Deska",
    email: "deska@gmail.com",
    phone: "342234553"
 }));
xhr.onload = function() {
    var data = JSON.parse(this.responseText);
    console.log(data);
};

Или, если вы хотите использовать fetch API

fetch(url, {
    method:"POST",
    body: JSON.stringify({
        name: "Deska",
        email: "deska@gmail.com",
        phone: "342234553"
        })
    })
    .then(result => {
        // do something with the result
        console.log("Completed with result:", result);
    });
Желание Калеба
источник
2

Знаете ли вы, что в JavaScript есть встроенные методы и библиотеки для создания форм и их отправки?

Я вижу здесь много ответов, в которых все просят использовать стороннюю библиотеку, что, на мой взгляд, является излишним.

Я бы сделал на чистом Javascript следующее:

<script>
function launchMyForm()
{
   var myForm = document.createElement("FORM");
   myForm.setAttribute("id","TestForm");
   document.body.appendChild(myForm);

// this will create a new FORM which is mapped to the Java Object of myForm, with an id of TestForm. Equivalent to: <form id="TestForm"></form>

   var myInput = document.createElement("INPUT");
   myInput.setAttribute("id","MyInput");
   myInput.setAttribute("type","text");
   myInput.setAttribute("value","Heider");
   document.getElementById("TestForm").appendChild(myInput);

// This will create an INPUT equivalent to: <INPUT id="MyInput" type="text" value="Heider" /> and then assign it to be inside the TestForm tags. 
}
</script>

Таким образом (A) вам не нужно полагаться на третьи стороны для выполнения работы. (B) Все это встроено во все браузеры, (C) быстрее, (D) работает, попробуйте.

Надеюсь, это поможет. ЧАС

Хайдер Сати
источник