Replies: 7 comments
-
Seems to me like you should serialize the FormData into a JSON string, return it to the client, then deserialize it in the client as an Object. This is what a quick google revealed, could be helpful. https://gomakethings.com/serializing-form-data-with-the-vanilla-js-formdata-object/ |
Beta Was this translation helpful? Give feedback.
-
Hi @jcs224, thanks for your reply (and sorry for my late reply). Here is what I have tried: This is the code in the oak server: // Create a new instance of FormData
const formData = new FormData();
// Add some key-value pairs to the FormData object
formData.append("key1", "value1");
formData.append("key2", "value2");
// Send the FormData object as the response to the client
context.response.body = formData; In the client, to receive it, I have this code: await fetch(`/myroute/get`, {
method: 'POST',
body: myFormData, // this is another FormData, that I sent from the client and read in the server with no problems
})
.then(fetch => fetch.formData())
.then(res => { console.log(res); }); If I try to read the response with Uncaught (in promise) TypeError: Could not parse content as FormData. If I try to read the response with Object { } I could also try to add this line before the oak response: context.response.headers.set("Content-Type", "multipart/form-data");
context.response.body = JSON.stringify(formData); But the result is the same. This is related to this possible bug (#400), which I I don't know if it has been solved or if there is any workaround or example code to accomplish the same need (to receive in the client an object from Deno Oak that contains many blobs+strings). Also, I am using the last version of Oak (11.1.0). |
Beta Was this translation helpful? Give feedback.
-
Using Insomnia, I receive the FormData that was created in the server. This is the code in the server: Router.post("http://localhost:7777/test", async (context) => {
const formData = new FormData();
formData.append("key1", "value1");
formData.append("key2", "value2");
context.response.body = formData;
}); And this is the result that Insomnia received: But If I use in the server let stringified = JSON.stringify(formData);
let parsed = JSON.parse(stringified)
console.info(parsed) // returns '{}' ?? So sending the response body without But the problem is that I can't receive that FormData in the browser, as I don't know how I can "parse" that response, because using |
Beta Was this translation helpful? Give feedback.
-
Oak can send // server
import { Application } from "https://deno.land/x/oak/mod.ts";
const app = new Application();
app.use((ctx) => {
const form = new FormData();
form.append("key1", "hello");
form.append("key2", "world");
ctx.response.body = form; // automatically adds the `content-type` response header
});
await app.listen({ port: 8000 }); When fetching the results, we can turn it back into a // client
const response = await fetch("http://localhost:8000");
const form = await response.formData(); It does seem like oak header didn't include the boundary and gives this error.
Looks like the response header is missing a boundary field. Response {
...
headers: Headers {
- "content-type": "multipart/form-data"
+ "content-type": "multipart/form-data"; boundary=---------------------------293582696224464 // should have this
}
...
}, |
Beta Was this translation helpful? Give feedback.
-
Hello @linhub15, many thanks for helping. The problem is that no matter which way I send the FormData from oak, the client doesn't receive it correctly. This line fails on the client browser: const form = await response.formData(); // returns TypeError: Could not parse content as FormData probably because of the missing "boundary", but I have tried to work around this in several ways. I have also tried using an npm package which can add the formData boundary: import formdata from "npm:form-data";
const formData = new formdata();
formData.append("key1", "value1");
context.response.headers.set('Content-Type', `multipart/form-data; boundary=${formData.getBoundary()}`)
context.response.body = formData; // still fails in the client The thing is, that using only "basic" Deno I can read correctly the FormData in the client browser, with a code like this: const server = Deno.listen({ port: 7000 });
for await (const conn of server) serveHttp(conn);
async function serveHttp(conn) {
const httpConn = Deno.serveHttp(conn);
for await (const requestEvent of httpConn) {
const data = new FormData();
data.append("string1", "Hi");
data.append("string2", "Bye");
data.append("blob1", new Blob(['<a id="a">Hi</a>'], { type: "text/xml" }));
data.append("blob2", new Blob(['<b id="b">Bye</b>'], { type: "text/xml" }));
requestEvent.respondWith(new Response(data));
}
}
So from what I understand this is an error in Oak, since if it worked in the same way that "standard" Deno does, the error would be fixed. I don't know if there is any solution to this, like using basic Deno to send FormData, in a parallel port. But from what I understand, I would need to have two active http ports etc, so it would be more of a mess. I also don't know if this problem is solved by other users in some other way, or if they simply don't need to send FormData responses from the server. In any case, I'm curious if you've managed to receive the FormData from Oak in a working example, using a browser as client (I managed to receive it using Curl or Insomnia, but not the browser). |
Beta Was this translation helpful? Give feedback.
-
I ended up using a solution based on Base64 string. It is very inefficient (as base64 encoding increments +33% the size of the file encoded) but it works. In the server: let URI_File = `/my/uri/file.mp4`;
const file = await Deno.open(URI_File);
const base64String = this.Lab.Library.base64Encode(await Deno.readAll(file));
const myObjectWithBlobs = {
myString: "hello",
myBlob: base64String
}
context.response.body = myObjectWithBlobs; In the client, decoding the base64 string: await fetch(`https://site.com/get`, { method: 'POST' })
.then(response => response.json())
.then(data => {
const decodedBase64 = atob(data.myBlob);
const arrayBuffer = new ArrayBuffer(decodedBase64.length);
const uint8Array = new Uint8Array(arrayBuffer);
for (let i = 0; i < decodedBase64.length; i++) {
uint8Array[i] = decodedBase64.charCodeAt(i);
}
// We get the blob (but many blobs could be send in the same response)
const blob = new Blob([arrayBuffer], { type: 'application/octet-stream' });
}); Hope that better solutions come in the future. If I encounter a better solution to this issue I will post it. |
Beta Was this translation helpful? Give feedback.
-
I might have some additional insight for people still bumping into this. You might need to include a filename for binary data fields in I was experiencing a similar issue with SvelteKit. Just like the OP, I wanted to send a I also wanted to use I also kept getting fetch/parsing issues on the client like The first one was explained by the missing boundary (thanks!), but the latter only happened when I tried sending a buffer, rather than a string. In that case, it turns out browsers (well, Chromium at least) requires a This worked for me: export const GET: RequestHandler = async () => {
const form = new FormData();
const buffer = await getData();
form.append('key1', buffer, {
filename: 'myfilename',
knownLength: buffer.length,
contentType: 'application/octet-stream'
});
return new Response(form.getBuffer(), {
headers: form.getHeaders()
});
} So maybe it was a missing filename? I'm including the |
Beta Was this translation helpful? Give feedback.
-
Is it possible to send a FormData as a
context.response.body
from the server (Deno/Oak) to the client (web browser)?In Firefox I receive the error: TypeError: Could not parse content as FormData and in Chrome it says: TypeError: Invalid MIME type when I try to receive the response using
response.formData()
.I can send a FormData from the client to the server with no problem, but I don't know if the other way around is possible.
Basically, what I want to do is send from the server an object-like which contains many blobs (images) in an all-in-one response.
Beta Was this translation helpful? Give feedback.
All reactions