由于无法使用Discord.js,我正尝试通过使用Webhook的香草javascript将单个PNG文件上传到Discord频道。
在Chrome的JavaScript控制台中,我收到以下错误消息:
POST https://discordapp.com/api/webhooks/ <我的不和谐webhook> 400
此console.log()
输出之后:
成功:{消息:“无法发送空消息”,代码:50006}
我在最后添加了我的代码和网络控制台记录,但我有1个问题:
Content-Disposition
类型为form-data
,与我的问题有任何联系吗?在此之前,我设法使用XMLHttpRequest和fetch来发布消息(仅json,没有文件)。
尽管我可以并且希望使用纯Javascript解决方案,但我没有尝试使用JQuery。
下面是我编写的代码,用于发送单个PNG图像以及有效负载_json JSON数据有效负载(没有有效负载时会发生相同的错误):
const filename = 'image.png';
domtoimage.toBlob(document.querySelector('<element to snapshot selector>'))
.then(function (blob) {
const formData = new FormData();
var params = {
username: "My bot name",
avatar_url: "",
content: "another test 2",
embeds: [{
"image": {
"url": "https://i.imgur.com/ZGPxFN2.jpg"
}
}]
};
formData.append('payload_json',JSON.stringify(params))
formData.append('file',blob);
fetch('https://discordapp.com/api/webhooks/<my discord webhook>', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
},
body: formData,
})
.then(response => response.json())
.then(result => {
console.log('Success:', result);
})
.catch(error => {
console.error('Error:', error);
});
});
在Chrome的网络控制台中,我获得以下信息:
General
Request URL: https://discordapp.com/api/webhooks/<my discord webhook>
Request Method: POST
Status Code: 400
Remote Address: 162.159.134.233:443
Referrer Policy: no-referrer-when-downgrade
Response Headers
access-control-allow-credentials: true
access-control-allow-headers: Content-Type, Authorization, X-Track, X-Super-Properties, X-Context-Properties, X-Failed-Requests, X-Fingerprint, X-RPC-Proxy, X-Debug-Options, x-client-trace-id, If-None-Match, X-RateLimit-Precision
access-control-allow-methods: POST, GET, PUT, PATCH, DELETE
access-control-allow-origin: <access-control-allow-origin>
access-control-expose-headers: Retry-After, X-RateLimit-Global, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-RateLimit-Bucket, Date
cf-cache-status: DYNAMIC
cf-ray: <cf-ray>
cf-request-id: <cf-request-id>
content-length: 58
content-type: application/json
date: Thu, 16 Jul 2020 04:23:41 GMT
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
server: cloudflare
set-cookie: __cfduid=<__cfduid>; expires=Sat, 15-Aug-20 04:23:40 GMT; path=/; domain=.discordapp.com; HttpOnly; SameSite=Lax
set-cookie: __cfruid=<__cfduid>; path=/; domain=.discordapp.com; HttpOnly; Secure; SameSite=None
status: 400
strict-transport-security: max-age=31536000; includeSubDomains
via: 1.1 google
x-envoy-upstream-service-time: 27
x-ratelimit-bucket: <x-ratelimit-bucket>
x-ratelimit-limit: 5
x-ratelimit-remaining: 4
x-ratelimit-reset: <x-ratelimit-reset>
x-ratelimit-reset-after: 2
Request Headers
:authority: discordapp.com
:method: POST
:path: /api/webhooks/<my discord webhook>
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en,en-US;q=0.9,ja;q=0.8
content-length: 50696
content-type: multipart/form-data
origin: https://<origin>
referer: https://<referer>
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
Request Payload
------WebKitFormBoundarypu7GvABzASKKKTQF
Content-Disposition: form-data; name="payload_json"
{"username":"WhiteBoard","avatar_url":"https://i.imgur.com/ZGPxFN2.jpg","content":"another test 2","embeds":[{"image":{"url":"https://i.imgur.com/ZGPxFN2.jpg"}}]}
------WebKitFormBoundarypu7GvABzASKKKTQF
Content-Disposition: form-data; name="file"; filename="blob"
Content-Type: image/png
‰PNG
IHDRpíã IDAT[...]
[...]:cjIEND®B`‚
------WebKitFormBoundarypu7GvABzASKKKTQF--
--------编辑(2020/07/16 14:30):我自己回答第二个问题--------
FormData.append()
接受文件名的第三个参数,我的代码应如下所示: formData.append('file',blob,filename);
答案 0 :(得分:3)
构建一个简单的 js 函数,在发送到服务器之前在客户端调整图像大小。 我得到了 base64 编码的结果并用这个函数制作了一个 blob
const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
然后,我将图像作为 blob 发送到带有 fetch 的 discord webhook
function sendMessage(img, obj=false) {
console.log("send")
const WH_URL = "YOUR_URL"
if(!obj)
obj = {
content: ''
}
var myHeaders = new Headers();
var formdata = new FormData();
formdata.append("file", img, "img.png");
formdata.append("payload_json", JSON.stringify(obj));
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: formdata,
redirect: 'follow'
};
fetch(WH_URL, requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
}
const resizeImage = data =>{
return new Promise( r =>{
let dst, ctx, width, start, time, _data;
let img = new Image();
img.src = data
img.onload = () => {
width = 300;
dst = document.createElement("canvas")
ctx = dst.getContext("2d")
dst.width = width;
dst.height = img.height * width / img.width
start = performance.now()
ctx.drawImage(img, 0, 0, dst.width, dst.height)
time = (performance.now() - start).toFixed(2)
_data = dst.toDataURL()
r(_data)
}
})
}
const readImg = async form =>{
var files = form.files;
if (files.length === 0)
return;
let data = await resizeImage(window.URL.createObjectURL(files[0]))
document.querySelector('#img').src = data;
let b64 = data.split(",")[1] // get only base64
sendMessage(b64toBlob(b64), { content: 'Resized Image'})
}
function sendMessage(img, obj=false) {
console.log("send")
const WH_URL = "YOUR_WEBHOOK_URL"
if(!obj)
obj = {
content: ''
}
var myHeaders = new Headers();
var formdata = new FormData();
formdata.append("file", img, "img.png");
formdata.append("payload_json", JSON.stringify(obj));
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: formdata,
redirect: 'follow'
};
fetch(WH_URL, requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
}
const b64toBlob = (b64Data, contentType='', sliceSize=512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {type: contentType});
return blob;
}
<img id="img"/>
<p>
<input type="file" onchange="readImg(this)"/>
</p>