获取 blob 错误 - net::ERR_CONTENT_LENGTH_MISMATCH 200(正常)
Fetch blob error - net::ERR_CONTENT_LENGTH_MISMATCH 200 (OK)
我有以下代码可以从我的节点 js express web 应用程序(通过 MS Azure 托管)的前端发出获取请求。
该请求适用于较小的 zip 文件 blob,但对于较大的 blob,它最终会超时并出现以下错误 - net::ERR_CONTENT_LENGTH_MISMATCH 200 (OK)
let requestURL = organisation + '-' + userID + '-' + jobRef + '.json';
fetch(`/downloadImages`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ requestURL: requestURL }),
})
.then(response => response.blob())
.then(function (blob) {
console.log('blob received');
download(blob, jobRef + ".zip");
document.getElementById('loaderBackground').classList.add('d-none');
})
.catch((e) => {
setTimeout(() => {
console.log(e);
alert('Error');
}, 1000);
});
这是我在 node.js express 文件夹中的 app.js
//'use strict';
var debug = require('debug');
var express = require('express');
var Path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var csrf = require('csurf');
var bodyParser = require('body-parser');
var http = require("https");
var favicon = require('serve-favicon');
const resolve = require("path").resolve;
var JsZip = require('jszip');
var fs = require('fs-extra');
const uuid = require("uuid");
var request = require('request');
var https = require('https');
const axios = require("axios");
const path = require("path");
const fsExtra = require("fs-extra");
var Scraper = require("image-scraper");
//ENVIRONMENT SETUP
const currentEnv = 'PROD'; //Either 'PROD' OR 'DEV'
const cloudinaryFolder = 'inspectAPP'; //Either 'inspectAPP' OR 'inspectAPP-dev'
// setup route middlewares
var csrfProtection = csrf({ cookie: true })
var app = express();
//Set up helmet
var helmet = require('helmet');
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", "cdnjs.cloudflare.com", "ajax.googleapis.com", "maxcdn.bootstrapcdn.com", "cdn.jsdelivr.net", "stackpath.bootstrapcdn.com"],
styleSrc: ["'self'", "'unsafe-inline'", "stackpath.bootstrapcdn.com", "fonts.googleapis.com", "cdnjs.cloudflare.com", "maxcdn.bootstrapcdn.com", "use.fontawesome.com"],
imgSrc: ["*", "'self'", "cdnjs.cloudflare.com"],
fontSrc: ["*", "'self'", "fonts.gstatic.com"],
frameSrc:["'self'","jimmywarting.github.io"],
objectSrc: ["'none'"],
connectSrc: ["'self'", "res.cloudinary.com", "cloudinary.com"],
upgradeInsecureRequests: [],
},
})
);
app.disable('x-powered-by');
// view engine setup
// view engine setup
app.set('views', Path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(favicon(__dirname + '/public/images/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(bodyParser.json());
// parse some custom thing into a Buffer
var rawOptions = {
inflate: true,
limit: '100mb',
type: 'application/octet-stream'
};
app.use(bodyParser.raw(rawOptions));
app.use(cookieParser());
app.use(express.static(Path.join(__dirname, 'public')));
//////////////////////////////////////////////////////////////////////////////////////////
// Rate limiting
//////////////////////////////////////////////////////////////////////////////////////////
const rateLimit = require("express-rate-limit");
const apiLimiter = rateLimit({
windowMs: 24 * 60 * 60 * 1000, // 24 hours
max: 50
});
// only apply to requests that begin with /api/
app.use("/signIn", apiLimiter);
//////////////////////////////////////////////////////////////////////////////////////////
// Photo management
//////////////////////////////////////////////////////////////////////////////////////////
var JSZip = require("jszip");
var request = require('request');
var archiver = require('archiver');
downloadImage = async (uri, filename, callback) => {
request.head(uri, function(err, res, body){
request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
});
};
app.get('/imageDownload', function (req, res) {
var organisation = req.query.organisation;
var jobRef = req.query.jobRef;
res.download('secureFiles/imageZips/' + organisation + '/' + jobRef + '.zip');
});
app.post("/downloadImages", async (req, res) => {
try {
const requestURL = req.body.requestURL;
console.log(requestURL)
const rootDirectory = process.cwd();
fsExtra.emptyDirSync(`${__dirname}/upload/`);
const getJsonFile = async () => {
try {
const resp = await axios.get(
`https://res.cloudinary.com/alvari/image/list/${requestURL}`
);
return resp.data.resources;
} catch (e) {
console.log(e);
res.status(500).send(e);
}
};
await getJsonFile();
const createZipFile = async () => {
const sourceDir = resolve(rootDirectory, "upload");
let zip = new JsZip();
buildZipFromDirectory(sourceDir, zip, sourceDir);
const zipContent = await zip.generateAsync({
type: "nodebuffer",
comment: "ser-web-manangement",
compression: "DEFLATE",
compressionOptions: {
level: 9,
},
});
return zipContent;
};
const buildZipFromDirectory = (dir, zip, root) => {
const list = fs.readdirSync(dir);
for (let file of list) {
file = path.resolve(dir, file);
let stat = fs.statSync(file);
if (stat && stat.isDirectory()) {
this.buildZipFromDirectory(file, zip, root);
} else {
const filedata = fs.readFileSync(file);
zip.file(path.relative(root, file), filedata);
}
}
};
const dest = `${__dirname}/upload/`;
var count = 0;
let src = await getJsonFile();
var recursiveDowload = async function (urlArray, i) {
if (i < urlArray.length) {
console.log(urlArray[i].public_id);
request
.get(
"https://res.cloudinary.com/alvari/image/upload/" +
urlArray[i].public_id
)
.on("error", function (err) {
console.log(err);
})
.pipe(
fs.createWriteStream(
`${__dirname}/upload/` +
`${urlArray[i].public_id.split("/")[1]}.` +
urlArray[i].format
)
)
.on("close", function () {
recursiveDowload(urlArray, i + 1);
});
} else {
const fileer = await createZipFile();
fsExtra.emptyDirSync(`${__dirname}/upload/`);
res.setHeader("content-type", "arrayBuffer");
res.send(fileer);
}
};
recursiveDowload(src, 0);
} catch (e) {
console.log(e);
fsExtra.emptyDirSync(`${__dirname}/upload/`);
res.status(500).send(e);
}
});
//////////////////////////////////////////////////////////////////////////////////////////
// Error handling
//////////////////////////////////////////////////////////////////////////////////////////
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
//err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error.pug', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error.pug', {
message: err.message,
error: {}
});
});
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept,Authorization"
);
next();
});
app.set('port', process.env.PORT || 3000);
var server = app.listen(app.get('port'), function () {
debug('Express server listening on port ' + server.address().port);
});
您可能应该配置 express 应用程序的最大文件大小。
app.use(bodyParser.json({limit: '100mb'}));
app.use(bodyParser.urlencoded({
limit: '100mb',
extended: true
}));
将 100mb 更改为适合您要求的大小。
我有以下代码可以从我的节点 js express web 应用程序(通过 MS Azure 托管)的前端发出获取请求。 该请求适用于较小的 zip 文件 blob,但对于较大的 blob,它最终会超时并出现以下错误 - net::ERR_CONTENT_LENGTH_MISMATCH 200 (OK)
let requestURL = organisation + '-' + userID + '-' + jobRef + '.json';
fetch(`/downloadImages`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ requestURL: requestURL }),
})
.then(response => response.blob())
.then(function (blob) {
console.log('blob received');
download(blob, jobRef + ".zip");
document.getElementById('loaderBackground').classList.add('d-none');
})
.catch((e) => {
setTimeout(() => {
console.log(e);
alert('Error');
}, 1000);
});
这是我在 node.js express 文件夹中的 app.js
//'use strict';
var debug = require('debug');
var express = require('express');
var Path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var csrf = require('csurf');
var bodyParser = require('body-parser');
var http = require("https");
var favicon = require('serve-favicon');
const resolve = require("path").resolve;
var JsZip = require('jszip');
var fs = require('fs-extra');
const uuid = require("uuid");
var request = require('request');
var https = require('https');
const axios = require("axios");
const path = require("path");
const fsExtra = require("fs-extra");
var Scraper = require("image-scraper");
//ENVIRONMENT SETUP
const currentEnv = 'PROD'; //Either 'PROD' OR 'DEV'
const cloudinaryFolder = 'inspectAPP'; //Either 'inspectAPP' OR 'inspectAPP-dev'
// setup route middlewares
var csrfProtection = csrf({ cookie: true })
var app = express();
//Set up helmet
var helmet = require('helmet');
app.use(
helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "'unsafe-inline'", "cdnjs.cloudflare.com", "ajax.googleapis.com", "maxcdn.bootstrapcdn.com", "cdn.jsdelivr.net", "stackpath.bootstrapcdn.com"],
styleSrc: ["'self'", "'unsafe-inline'", "stackpath.bootstrapcdn.com", "fonts.googleapis.com", "cdnjs.cloudflare.com", "maxcdn.bootstrapcdn.com", "use.fontawesome.com"],
imgSrc: ["*", "'self'", "cdnjs.cloudflare.com"],
fontSrc: ["*", "'self'", "fonts.gstatic.com"],
frameSrc:["'self'","jimmywarting.github.io"],
objectSrc: ["'none'"],
connectSrc: ["'self'", "res.cloudinary.com", "cloudinary.com"],
upgradeInsecureRequests: [],
},
})
);
app.disable('x-powered-by');
// view engine setup
// view engine setup
app.set('views', Path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(favicon(__dirname + '/public/images/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(bodyParser.json());
// parse some custom thing into a Buffer
var rawOptions = {
inflate: true,
limit: '100mb',
type: 'application/octet-stream'
};
app.use(bodyParser.raw(rawOptions));
app.use(cookieParser());
app.use(express.static(Path.join(__dirname, 'public')));
//////////////////////////////////////////////////////////////////////////////////////////
// Rate limiting
//////////////////////////////////////////////////////////////////////////////////////////
const rateLimit = require("express-rate-limit");
const apiLimiter = rateLimit({
windowMs: 24 * 60 * 60 * 1000, // 24 hours
max: 50
});
// only apply to requests that begin with /api/
app.use("/signIn", apiLimiter);
//////////////////////////////////////////////////////////////////////////////////////////
// Photo management
//////////////////////////////////////////////////////////////////////////////////////////
var JSZip = require("jszip");
var request = require('request');
var archiver = require('archiver');
downloadImage = async (uri, filename, callback) => {
request.head(uri, function(err, res, body){
request(uri).pipe(fs.createWriteStream(filename)).on('close', callback);
});
};
app.get('/imageDownload', function (req, res) {
var organisation = req.query.organisation;
var jobRef = req.query.jobRef;
res.download('secureFiles/imageZips/' + organisation + '/' + jobRef + '.zip');
});
app.post("/downloadImages", async (req, res) => {
try {
const requestURL = req.body.requestURL;
console.log(requestURL)
const rootDirectory = process.cwd();
fsExtra.emptyDirSync(`${__dirname}/upload/`);
const getJsonFile = async () => {
try {
const resp = await axios.get(
`https://res.cloudinary.com/alvari/image/list/${requestURL}`
);
return resp.data.resources;
} catch (e) {
console.log(e);
res.status(500).send(e);
}
};
await getJsonFile();
const createZipFile = async () => {
const sourceDir = resolve(rootDirectory, "upload");
let zip = new JsZip();
buildZipFromDirectory(sourceDir, zip, sourceDir);
const zipContent = await zip.generateAsync({
type: "nodebuffer",
comment: "ser-web-manangement",
compression: "DEFLATE",
compressionOptions: {
level: 9,
},
});
return zipContent;
};
const buildZipFromDirectory = (dir, zip, root) => {
const list = fs.readdirSync(dir);
for (let file of list) {
file = path.resolve(dir, file);
let stat = fs.statSync(file);
if (stat && stat.isDirectory()) {
this.buildZipFromDirectory(file, zip, root);
} else {
const filedata = fs.readFileSync(file);
zip.file(path.relative(root, file), filedata);
}
}
};
const dest = `${__dirname}/upload/`;
var count = 0;
let src = await getJsonFile();
var recursiveDowload = async function (urlArray, i) {
if (i < urlArray.length) {
console.log(urlArray[i].public_id);
request
.get(
"https://res.cloudinary.com/alvari/image/upload/" +
urlArray[i].public_id
)
.on("error", function (err) {
console.log(err);
})
.pipe(
fs.createWriteStream(
`${__dirname}/upload/` +
`${urlArray[i].public_id.split("/")[1]}.` +
urlArray[i].format
)
)
.on("close", function () {
recursiveDowload(urlArray, i + 1);
});
} else {
const fileer = await createZipFile();
fsExtra.emptyDirSync(`${__dirname}/upload/`);
res.setHeader("content-type", "arrayBuffer");
res.send(fileer);
}
};
recursiveDowload(src, 0);
} catch (e) {
console.log(e);
fsExtra.emptyDirSync(`${__dirname}/upload/`);
res.status(500).send(e);
}
});
//////////////////////////////////////////////////////////////////////////////////////////
// Error handling
//////////////////////////////////////////////////////////////////////////////////////////
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
//err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error.pug', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error.pug', {
message: err.message,
error: {}
});
});
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept,Authorization"
);
next();
});
app.set('port', process.env.PORT || 3000);
var server = app.listen(app.get('port'), function () {
debug('Express server listening on port ' + server.address().port);
});
您可能应该配置 express 应用程序的最大文件大小。
app.use(bodyParser.json({limit: '100mb'}));
app.use(bodyParser.urlencoded({
limit: '100mb',
extended: true
}));
将 100mb 更改为适合您要求的大小。