简体   繁体   English

纯 JavaScript 在没有表单的情况下发送 POST 数据

[英]Pure JavaScript Send POST Data Without a Form

Is there a way to send data using the POST method without a form and without refreshing the page using only pure JavaScript (not jQuery $.post() )?有没有办法在没有表单的情况下使用 POST 方法发送数据,并且只使用纯 JavaScript(不是 jQuery $.post() )刷新页面? Maybe httprequest or something else (just can't find it now)?也许是httprequest或其他东西(只是现在找不到)?

You can send it and insert the data to the body:您可以发送它并将数据插入正文:

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

By the way, for get request:顺便说一下,对于获取请求:

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();

The [new-ish at the time of writing in 2017] Fetch API is intended to make GET requests easy, but it is able to POST as well. [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);
});

If you are as lazy as me (or just prefer a shortcut/helper):如果你和我一样懒惰(或者只是喜欢快捷方式/帮手):

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

// ...

post("post/data/here", {element: "osmium"});

You can use the XMLHttpRequest object as follows:您可以按如下方式使用XMLHttpRequest对象:

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

That code would post someStuff to url .该代码会将someStuff发布到url Just make sure that when you create your XMLHttpRequest object, it will be cross-browser compatible.只需确保在创建XMLHttpRequest对象时,它将是跨浏览器兼容的。 There are endless examples out there of how to do that.有无数的例子来说明如何做到这一点。

Also, RESTful lets you get data back from a POST request.此外,REST风格让你从一个POST请求的数据备份

JS (put in static/hello.html to serve via Python): 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 server (for testing): 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)

Console log (chrome):控制台日志(镀铬):

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

Console log (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 }

Console log (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 log: Python日志:

HTTP 8/postman[post]: PATH='/postman'
URL 8/postman[post]: request data = {"value":"value"}
URL 8/postman[post]: response data = {"req": {"value": "value"}}

You can use XMLHttpRequest, fetch API, ...您可以使用 XMLHttpRequest、获取 API、...

If you want to use XMLHttpRequest you can do the following如果您想使用 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);
};

Or if you want to use fetch API或者如果你想使用 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);
    }).catch(err => {
        // if any error occured, then catch it here
        console.error(err);
    });

There is an easy method to wrap your data and send it to server as if you were sending an HTML form using POST .有一种简单的方法可以包装数据并将其发送到服务器,就像使用POST发送 HTML 表单一样。 you can do that using FormData object as following:您可以使用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)

now you can handle the data on the server-side just like the way you deal with reugular HTML Forms.现在您可以像处理常规 HTML 表单一样在服务器端处理数据。

Additional Info附加信息

It is advised that you must not set Content-Type header when sending FormData since the browser will take care of that.建议您在发送 FormData 时不要设置 Content-Type 标头,因为浏览器会处理这些。

navigator.sendBeacon() navigator.sendBeacon()

If you simply need to POST data and do not require a response from the server, the shortest solution would be to use navigator.sendBeacon() :如果您只需要POST数据并且不需要来自服务器的响应,最短的解决方案是使用navigator.sendBeacon()

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

navigator.sendBeacon('example.php', data);

Did you know that JavaScript has it's built-in methods and libs to create forms and submit them?您是否知道 JavaScript 具有创建表单和提交表单的内置方法和库?

I am seeing a lot of replies here all asking to use a 3rd party library which I think is an overkill.我在这里看到很多回复都要求使用 3rd 方库,我认为这有点矫枉过正。

I would do the following in pure 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>

This way (A) you don't need to rely on 3rd parties to do the job.这样 (A) 你不需要依赖 3rd 方来完成这项工作。 (B) It's all built-in to all browsers, (C) faster, (D) it works, feel free to try it out. (B) 所有浏览器都内置了它,(C) 更快,(D) 它可以工作,请随意尝试。

I hope this helps.我希望这有帮助。 H H

const data = { username: 'example' };

fetch('https://example.com/profile', {
  method: 'POST', // or 'PUT'
  headers: {
 '           Content-Type': 'application/json',
           },
  body: JSON.stringify(data),
})
  .then(response => response.json())
  .then(data => {
      console.log('Success:', data);
     })
 .catch((error) => {
         console.error('Error:', error);
   });

The most popular answers here do not show how to get data back from the POST.这里最流行的答案没有显示如何从 POST 取回数据。 Also, the popular "fetch" solutions do not work in the latest version of Chrome when sending data to the latest version of NodeJS unless you pass headers and also unwrap the response.json() promise.此外,当将数据发送到最新版本的 NodeJS 时,流行的“获取”解决方案在最新版本的 Chrome 中不起作用,除非您传递标头并解开 response.json() 承诺。 Also, the popular answers do not use async/await.此外,流行的答案不使用 async/await。

Here is the cleanest and most complete solution I could come up with that works.这是我能想出的最干净、最完整的解决方案。

async function postJsonData(jsonObject) {
    const response = await fetch("/echo", {
        method: "POST",
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify(jsonObject)
    });
    
    const actualResponse = await response.json();
}

Here is a nice function you (or anyone else) could use in their code:这是您(或其他任何人)可以在他们的代码中使用的一个很好的函数:

function post(url, data) {
    return new Promise((res, rej) => {
        let stringified = "";
        for (const [key, value] of Object.entries(data))
            stringified += `${stringified != '' ? '&' : ''}${key}=${value}`

        const xhr = new XMLHttpRequest();
        xhr.onreadystatechange = () => {
            if (xhr.readyState == 4)
                if (xhr.status == 200)
                    res(xhr.responseText)
                else
                    rej({ code: xhr.status, text: xhr.responseText })
        }
        xhr.open("POST", url, true);
        xhr.setRequestHeader('Content-Type', 'application/json');
        xhr.send(stringified);
    })
}

use this func of jbezz library使用 jbezz 库的这个函数

var makeHttpObject = function () {
  try {return new XMLHttpRequest();}
  catch (error) {}
  try {return new ActiveXObject("Msxml2.XMLHTTP");}
  catch (error) {}
  try {return new ActiveXObject("Microsoft.XMLHTTP");}
  catch (error) {}
  throw new Error("Could not create HTTP request object.");
}
function SendData(data){
    let type = (data.type ? data.type : "GET")
    let DataS = data.data;
    let url = data.url;
    let func = (data.success ? data.success : function(){})
    let funcE =(data.error ? data.error : function(){})
    let a_syne = (data.asyne ? data.asyne : false); 
    let u = null;
    try{u = new URLSearchParams(DataS).toString();}catch(e){u = Object.keys(DataS).map(function(k) {return encodeURIComponent(k) + '=' + encodeURIComponent(DataS[k])}).join('&')}
    if(type == "GET"){url +="?"+u}
    const xhttp =  makeHttpObject();
    xhttp.onload = function(){func(this.responseText)}
    xmlHttp.onreadystatechange = function() {if (xmlHttp.readyState == 4) 
    {if(xmlHttp.status !== 200){funcE(xmlHttp.statusText)}}}
    xhttp.open(type,url,a_syne);
    xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhttp.send(u);
}

use this to run :使用它来运行:

SendData({
    url:"YOUR_URL",
    asyne:true,
    type:"POST", // or GET
    data:{
        username:"ali",
        password:"mypass" // Your Data
    },
    success:function(Result){
        console.log(Result)
    },
    error:function(e){
        console.log("We Have Some Error")
    }
});

Or或者

download jbezz and add to your page.下载jbezz并添加到您的页面。

download link : github.com下载链接: github.com

use :用 :

$$.api({
        url:"YOUR_URL",
        asyne:true,
        type:"POST", // or GET
        data:{
            username:"ali",
            password:"mypass" // Your Data
        },
        success:function(Result){
            console.log(Result)
        },
        error:function(e){
            console.log("We Have Some Error")
        }
    });

You can also use this: https://github.com/floscodes/JS/blob/master/Requests.js你也可以使用这个: https : //github.com/floscodes/JS/blob/master/Requests.js

You can easily send a http-Request.您可以轻松发送 http-Request。 Just use:只需使用:

HttpRequest("https://example.com", method="post", data="yourkey=yourdata");

That's it!而已! It should even work if the site is CSRF-protected.如果站点受 CSRF 保护,它甚至应该可以工作。

Or just send a GET-Request by using或者只是使用发送 GET-Request

HttpRequest("https://example.com", method="get");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM