So I've been trying to implement image upload to Backblaze B2 bucket for about three days now. I struggled with getting the data, but I'm getting an error about connection refusing I guess. It returns error code 504 and I've tried fixing it by sending just the image, without converting it to base64 data. I don't understand a lot about base64 data, so I think the error might be caused by base64Data. I also don't have a lot of experience with backblaze-b2 and found the npm package "backblaze-b2" not too long ago. Here's the code:
const B2 = require('backblaze-b2');
const fs = require('fs');
export const uploadImage = async (req, res) => {
try {
const b2 = new B2({
accountId: process.env.BACKBLAZE_ACCOUNT_ID,
applicationKey: process.env.BACKBLAZE_APPLICATION_MASTER_KEY,
});
await b2.authorize();
// console.log(req.body);
const { image } = req.body;
if (!image) return res.status(400).send('No image found!');
// prepare the image
const base64Data = new Buffer.from(
image.replace(/^data:image\/\w+;base64,/,""),
'base64'
);
const handleImage = async () => {
try {
let uploadUrl = await b2.getUploadUrl({
bucketId: process.env.BACKBLAZE_BUCKET_ID,
});
// console.log('Is this not working?', uploadUrl);
const data = b2.uploadFile({
uploadUrl: uploadUrl.data.bucketId,
uploadAuthToken: uploadUrl.data.authorizationToken,
fileName: 'Pepe', //<-- TODO: Fix later
data: base64Data, // <-- Figure out what to pass in
onUploadProgress: (e) => null,
});
console.log(data);
res.send(data);
} catch (err) {
console.log('Bucket error or something: ', err);
}
};
handleImage();
} catch (err) {
console.log(err);
}
};
Here's the console:
Server is running on port 8000
DB CONNECTED
GET /api/csrf-token 200 2.732 ms - 52
GET /api/current-instructor 304 176.213 ms - -
Bucket error or something: Error: connect ECONNREFUSED 127.0.0.1:80
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1132:16) {
errno: -4078,
code: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 80,
config: {
url: 'deleted, for safety reasons',
method: 'post',
data: <Buffer ff d8 ff e0 00 10 4a 46 49 46 00 01 01 00 00 01 00 01 00 00 ff e2 02 28 49 43 43 5f 50 52 4f 46
49 4c 45 00 01 01 00 00 02 18 00 00 00 00 02 10 00 00 ... 71126 more bytes>,
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'b2/x-auto',
Authorization: 'deleted, for safety reasons',
'Content-Length': 71176,
'X-Bz-File-Name': 'Pepe',
'X-Bz-Content-Sha1': 'deleted, for safety reasons(possibly)',
'User-Agent': 'axios/0.21.4'
},
transformRequest: [ [Function (anonymous)] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
adapter: [Function: httpAdapter],
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
onUploadProgress: [Function: onUploadProgress],
maxContentLength: -1,
maxBodyLength: -1,
maxRedirects: 0,
validateStatus: [Function: validateStatus],
transitional: {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false
},
'axios-retry': { retryCount: 3, lastRequestTime: 1635347528124 }
},
request: <ref *1> ClientRequest {
_events: [Object: null prototype] {
response: [Function],
error: [Function: handleRequestError]
},
_eventsCount: 2,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: false,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: true,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 71176,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
_closed: false,
socket: Socket {
connecting: false,
_hadError: true,
_parent: null,
_host: 'localhost',
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 8,
_maxListeners: undefined,
_writableState: [WritableState],
allowHalfOpen: false,
_sockname: null,
_pendingData: [Array],
_pendingEncoding: '',
server: null,
_server: null,
parser: null,
_httpMessage: [Circular *1],
[Symbol(async_id_symbol)]: 325,
[Symbol(kHandle)]: null,
[Symbol(kSetNoDelay)]: false,
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: null,
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kCapture)]: false,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0
},
_header: 'POST deleted, for safety reasons HTTP/1.1\r\n' +
'Accept: application/json, text/plain, */*\r\n' +
'Content-Type: b2/x-auto\r\n' +
'Authorization: deleted, for safety reasons=\r\n' +
'Content-Length: 71176\r\n' +
'X-Bz-File-Name: Pepe\r\n' +
'X-Bz-Content-Sha1: deleted, for safety reasons\r\n' +
'User-Agent: axios/0.21.4\r\n' +
'Host: localhost\r\n' +
'Connection: close\r\n' +
'\r\n',
_keepAliveTimeout: 0,
_onPendingData: [Function: nop],
agent: Agent {
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
defaultPort: 80,
protocol: 'http:',
options: [Object: null prototype],
requests: [Object: null prototype] {},
sockets: [Object: null prototype],
freeSockets: [Object: null prototype] {},
keepAliveMsecs: 1000,
keepAlive: false,
maxSockets: Infinity,
maxFreeSockets: 256,
scheduling: 'lifo',
maxTotalSockets: Infinity,
totalSocketCount: 1,
[Symbol(kCapture)]: false
},
socketPath: undefined,
method: 'POST',
maxHeaderSize: undefined,
insecureHTTPParser: undefined,
path: 'deleted, for safety reasons',
_ended: false,
res: null,
aborted: false,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
reusedSocket: false,
host: 'localhost',
protocol: 'http:',
[Symbol(kCapture)]: false,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype] {
accept: [Array],
'content-type': [Array],
authorization: [Array],
'content-length': [Array],
'x-bz-file-name': [Array],
'x-bz-content-sha1': [Array],
'user-agent': [Array],
host: [Array]
}
},
response: undefined,
isAxiosError: true,
toJSON: [Function: toJSON]
}
Any help would be appreciated. Thanks.
There are a few changes I made to get this working:
bodyParser.raw()
to parse the body into the Buffer format that the backblaze-b2 library is expecting. It doesn't want base64.uploadUrl.data.bucketId
in the call to b2.uploadFile
to uploadUrl.data.uploadUrl.data.uploadUrl
. This is what was causing the 'connection refused' error. Since the uploadUrl
wasn't a URL, I'm guessing that b2.uploadFile
assumed it was a path and you wanted to connect to localhost.b2.uploadFile
.response.data
rather than just response
to see the API response.I built out your code into a runnable sample:
// I like to put my env vars in a .env file
const dotenv = require('dotenv');
dotenv.config();
const B2 = require('backblaze-b2');
const fs = require('fs');
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const port = process.env.PORT || 3000
const uploadImage = async (req, res) => {
try {
const b2 = new B2({
accountId: process.env.BACKBLAZE_ACCOUNT_ID,
applicationKey: process.env.BACKBLAZE_APPLICATION_MASTER_KEY,
});
await b2.authorize();
// console.log("req.body:", req.body);
if (!req.body) return res.status(400).send('No image found!');
const handleImage = async () => {
try {
let uploadUrl = await b2.getUploadUrl({
bucketId: process.env.BACKBLAZE_BUCKET_ID,
});
// Make the JSON more readable
console.log('getUploadUrl:', JSON.stringify(uploadUrl.data, undefined, 2));
// uploadFile returns a promise, so we need to await the response
const response = await b2.uploadFile({
uploadUrl: uploadUrl.data.uploadUrl,
uploadAuthToken: uploadUrl.data.authorizationToken,
fileName: 'Pepe', //<-- TODO: Fix later
data: req.body, // <-- This is the raw data as a buffer
onUploadProgress: (e) => null,
});
const prettyResponse = JSON.stringify(response.data, undefined, 2);
console.log('uploadFile: ', prettyResponse);
res.send(prettyResponse);
} catch (err) {
console.log('Bucket error or something: ', err);
}
};
handleImage();
} catch (err) {
console.log(err);
}
};
app.use(bodyParser.raw({ // Raw mode returns the posted body as a Buffer
type: '*/*' // Parse any mime type
}))
app.post('/', function (req, res) {
uploadImage(req, res)
})
app.listen(port, () => {
console.log(`Listening at http://localhost:${port}`)
})
Send a file with curl:
curl http://localhost:3000/ --data-binary @image.png
Console output (somewhat redacted!):
Listening at http://localhost:3000
getUploadUrl: {
"authorizationToken": "********",
"bucketId": "********",
"uploadUrl": "https://********.backblaze.com/b2api/v2/b2_upload_file/********"
}
uploadFile: {
"accountId": "********",
"action": "upload",
"bucketId": "********",
"contentLength": 3802,
"contentMd5": "d9b8b28f7fda3acfe7838ead41d8df38",
"contentSha1": "f8040f1068715160ef98ab98fde80f9214cb2845",
"contentType": "application/octet-stream",
"fileId": "********",
"fileInfo": {},
"fileName": "Pepe",
"fileRetention": {
"isClientAuthorizedToRead": true,
"value": {
"mode": null,
"retainUntilTimestamp": null
}
},
"legalHold": {
"isClientAuthorizedToRead": true,
"value": null
},
"serverSideEncryption": {
"algorithm": null,
"mode": null
},
"uploadTimestamp": 1641496698000
}