简体   繁体   中英

How to send/receive data to/from server via JS fetch

I'm new to fetch and I'm trying to convert $ajax into fetch without await, async.. (I didn't make it till there). I'm using Express for the server.

The fundamental concept of fetch/promise is unclear for me and I don't know how can I send the parameter selected in JSON format, and how to receive it from the server. I thought I would be ok to receive it (from server-side) with JSON.parse(req.body.data) , and I tried several things with it but it keeps giving me errors both on client-side and server-side(errors are down below).

** I tried Fetch: POST json data from someone's feedback but sadly I couldn't make it work for me. **

Any help would be appreciated.

addProduct(selected) { 
        const orderList = this;

        function post(){
        
            // const data = {
            //     selected:"selected",
            // }        

            fetch('/cart', {
                method:'post',
                headers:{
                    "Accept": "application/json, text/plain, */*",
                    "Content-type": "application/json; charset = UTF-8"
                },
                body: JSON.stringify(selected),
            })
            .then(res => {
                res.json()
                console.log(res)})
            .then(res => console.log(res));
        }
        
        post();
}

server-side error: SyntaxError: Unexpected token u in JSON at position 0

client-side error: Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0

(the following codes are the original $ajax code that works)

Client-side

menuItemClick(target) {
        const selected = this.menuList.data.find(product => product.id == target.dataset.id)
        const selectedIndex = this.orderList.data.findIndex(product => product.id == selected.id)
        if (selectedIndex === -1) {
            selected.count = 1;
            this.orderList.addProduct(selected)
    }



addProduct(selected) { 
        const orderList = this;
        $.ajax({
            url:"http://localhost:8080/cart",
            type:"post",
            dataType: "json",
            data: {data:JSON.stringify(selected)},
            success: function(orderedItem){
                orderList.data.push(orderedItem),
                orderList.orderRender()
            }
        })
        
    }

Server-side

app.use(express.json());
app.use(express.urlencoded({ extended: false }));

app.post("/cart", (req, res) => {
    const bodyData = JSON.parse(req.body.data);
    db.query(
        `INSERT INTO cartData (prodId) VALUES(${bodyData.id})`,(err, rows) => {
            db.query(
                `SELECT cartData.id as orderId, prodName, price, category, count, menuData.Id as id FROM menuData JOIN cartData on menuData.id = cartData.prodId where prodId = ${bodyData.id}`,
                (err, orderedItem) => {
                    res.send({"orderedItem": "${orderedItem[0]}"});
                }
            );
        }
    );
});

You're really close, just a few things:

  1. (Client side) You need to check for HTTP success. Unfortunately, fetch only rejects its promise when there's a network failure, not an HTTP error.

  2. (Client side) You need to use the return value of res.json() , which is a promise, so you want to return it from the fulfillment handler.

  3. (Client side) You need to either handle errors, or return the promise chain to something that will.

  4. (Server side) You're sending the text [object Object] , not JSON; more below.

  5. (Server side) The error you're getting suggests there's some other problem with the server-side code; more below.

  6. (Server side) Your code is at risk of SQL injection attacks ; more below.

So for example, if you want to handle errors in post and not have post report success/failure to its calller:

fetch('/cart', {
    method:'post',
    headers:{
        "Accept": "application/json, text/plain, */*",
        "Content-type": "application/json; charset = UTF-8"
    },
    body: JSON.stringify(selected),
})
.then(res => {
    if (!res.ok) {                                   // ***
        throw new Error("HTTP error " + res.status); // *** #1
    }                                                // ***
    return res.json();                               // *** #2
})
.then(data => {
    // *** Use `data` here
})
.catch(error => {
    // *** Handle/report error here                  // *** #3
});

Regarding #4, you're doing this to send the information:

res.send({"orderedItem": "${orderedItem[0]}"});

send expects a Buffer, a string, or an Array. To convert something to JSON and send that instead, use json :

res.json({"orderedItem": "${orderedItem[0]}"});

Also note that that will send exactly this JSON:

{"orderedItem":"${orderedItem[0]}"}

I suspect you wanted a template literal there so that the value of orderedItem[0] was sent, like this:

res.json({"orderedItem": `${orderedItem[0]}`});
// −−−−−−−−−−−−−−−−−−−−−−^−−−−−−−−−−−−−−−−−^

But if it's just orderedItem[0] , you don't need a template literal, just:

res.json({"orderedItem": orderedItem[0]});

or if you want to convert it to string:

res.json({"orderedItem": String(orderedItem[0])});

(You also don't need the " on the orderedItem property name because you're using an object literal there, you're not writing the JSON; but they're harmless in this case, and would be needed if you had a property name with a - or something in it.)

Regarding #5, you've said the error is:

Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0

That suggests that you're getting an error, not data, because the first token in what you were sending wouldn't have been a < but it would be if you were sending an HTML error page instead. Hopefully thanks to #2 above you'll now be taking the error path and will be able to find out what that error is. It's not immediately obvious from the code you've shown what that error is (unless bodyData.id is textual, not numeric), so you'll need to debug it.

Regarding #6, you have this template literal you're using to create your SQL:

`INSERT INTO cartData (prodId) VALUES(${bodyData.id})`

NEVER use information you've received from the client without sanitizing it. In that template literal, you've just accepted what was provided. The problem is that it could be something malicious, or just something whimsical. (Let me introduce you to my friend Bobby .)

Instead, use the feature of whatever it is providing db to create a parameterized query . Never use text concatenation with client-supplied values to build SQL strings.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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