简体   繁体   English

MEAN堆栈文件上传

[英]MEAN stack file upload

I am developing a MEAN stack web application and I want to upload file using ng2-file-upload. 我正在开发一个MEAN堆栈Web应用程序,我想使用ng2-file-upload上传文件。 This is my Angular 2 code. 这是我的Angular 2代码。

classroom.component.html classroom.component.html

    <input type="file" class="form-control" name="single" ng2FileSelect [uploader]="uploader" />
    <button type="button" class="btn btn-success btn-s"
                  (click)="uploader.uploadAll()" [disabled]="!uploader.getNotUploadedItems().length">
            <span class="glyphicon glyphicon-upload"></span> Upload all
          </button><br />

classroom.component.ts classroom.component.ts

uploader:FileUploader = new FileUploader({url: "http://localhost:3000/api/material/create-material"});

In server.js 在server.js中

app.use(cors());
app.use('/api',api);
app.use('/api/material',material);

and in material.js 并在material.js

var storage = multer.diskStorage({ //multers disk storage settings
    destination: function (req, file, cb) {
        cb(null, './uploads/');
    },
    filename: function (req, file, cb) {
        var datetimestamp = Date.now();
        cb(null, file.fieldname + '-' + datetimestamp + '.' + file.originalname.split('.')[file.originalname.split('.').length -1]);
    }
});

var upload = multer({ //multer settings
    storage: storage
}).single('file');

router.post('/create-material',passport.authenticate('jwt', {session: false}),function (req, res) {

    upload(req,res,function(err){
        console.log(req.file);
        if(err){
            res.json({error_code:1,err_desc:err});
            return;
        }
        //res.json({error_code:0,err_desc:null});
    });
});

When uploading a file I get following error 上传文件时出现以下错误

XMLHttpRequest cannot load http://localhost:3000/api/material/create-material . XMLHttpRequest无法加载http:// localhost:3000 / api / material / create-material Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. 对预检请求的响应未通过访问控制检查:当请求的凭据模式为“包含”时,响应中的“Access-Control-Allow-Origin”标头的值不能是通配符“*”。 Origin ' http://localhost:4200 ' is therefore not allowed access. 因此不允许来源' http:// localhost:4200 '访问。 The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute. XMLHttpRequest发起的请求的凭据模式由withCredentials属性控制。

What is the reason for this? 这是什么原因?

Add following to your nodejs middleware - 将以下内容添加到您的nodejs中间件 -

app.use(function (req, res, next) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
    res.setHeader('Access-Control-Allow-Credentials', true);

    next();
});

The CORS supports *, null or the exact protocol + domain + port as per -> http://www.w3.org/TR/cors/#access-control-allow-origin-response-header CORS支持*,null或精确的协议+域+端口 - > http://www.w3.org/TR/cors/#access-control-allow-origin-response-header

Server will need to validate the origin header using the regex, and then you can echo the origin value in the Access-Control-Allow-Origin response header. 服务器需要使用正则表达式验证原始标头,然后您可以在Access-Control-Allow-Origin响应标头中回显原始值。

The problem here is you are running two apps 这里的问题是你正在运行两个应用程序

  1. Angular 2 app with port number 4200 Angular 2 app,端口号为4200
  2. MEAN stack app with port number 3000 MEAN堆栈应用程序端口号为3000

So when Angular 2 app tries to do any calls to MEAN stack app which has port number "3000" browser will complain as it will be treated as cross domain ajax. 因此,当Angular 2应用程序尝试对端口号为“3000”的MEAN堆栈应用程序进行任何调用时,浏览器会抱怨,因为它将被视为跨域ajax。 To solve the cross domain ajax you will have to add the following lines of code in your MEAN stack app. 要解决跨域ajax,您必须在MEAN堆栈应用程序中添加以下代码行。

app.use(function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
});

If you really dont like doing this, then you have to do following steps. 如果您真的不喜欢这样做,那么您必须执行以下步骤。

  1. First build the angular app to deploy directly under MEAN stack app using "ng build". 首先构建角度应用程序,使用“ng build”直接在MEAN堆栈应用程序下部署。
  2. This will generate "dist" folder in angular app. 这将在角应用程序中生成“dist”文件夹。
  3. Move this dist folder under root folder of MEAN stack app and add following lines of code 将此dist文件夹移动到MEAN堆栈应用程序的根文件夹下,并添加以下代码行

    app.use(express.static(path.join(__dirname, 'dist'), {index: false})); app.use(express.static(path.join(__ dirname,'dist'),{index:false}));
    app.get('/', function (req, res) { res.sendFile(path.join(__dirname + '/dist/index.html')); }); app.get('/',function(req,res){res.sendFile(path.join(__ dirname +'/ didist / index.html'));});

By doing the above steps we are running only one app that is under MEAN stack and front-end will be served from angular generated markup from dist folder. 通过执行上述步骤,我们只运行一个位于MEAN堆栈下的应用程序,前端将通过dist文件夹中的角度生成标记提供服务。

ng2-file-upload has option to specify withcredentials for each file. ng2-file-upload具有为每个文件指定withcredentials选项。

Override onAfterAddingFile and set withCredentials = false for each file. 覆盖onAfterAddingFile并为每个文件设置withCredentials = false

eg: this.uploader.onAfterAddingFile = (fileItem:any) => { fileItem.withCredentials = false; } 例如: this.uploader.onAfterAddingFile = (fileItem:any) => { fileItem.withCredentials = false; } this.uploader.onAfterAddingFile = (fileItem:any) => { fileItem.withCredentials = false; }

This will solve your problem. 这将解决您的问题。 For more details: ng2-file-upload/src/file-upload/file-item.class.ts 有关更多详细信息: ng2-file-upload / src / file-upload / file-item.class.ts

Your node.js code will go like this 你的node.js代码将是这样的

var express=require("express");
var multer=require("multer");
var app=express();
var upload=multer({dest:"//destination where you want to upload<folder name>"});
app.post("//routing",upload.single('<variable-name>'),function(req,res){
    console.log("File Uploaded");
});
app.listen(//<port-number>);

Most of the given answers here are correct for implementations where you have two apps running and your need to set correct CORS headers so they can communicate via the browser. 这里给出的大多数答案都适用于您运行两个应用程序并且需要设置正确的CORS标头以便它们可以通过浏览器进行通信的实现。 In your particular case however, the issue is that you are using localhost for development. 但是,在您的特定情况下,问题是您使用localhost进行开发。

The issue is that Access-Control-Allow-Origin: * doesn't match localhost . 问题是Access-Control-Allow-Origin:*与localhost不匹配 Given you've set the correct CORS headers for your OPTIONS requests as the other answers suggest, you're preflight request will return the correct headers, but chrome doesn't acknowledge localhost as a valid domain matching * , and will fail the preflight check. 鉴于您已按照其他答案建议为您的OPTIONS请求设置了正确的CORS标头,您的预检请求将返回正确的标头,但chrome不会将localhost确认为匹配*的有效域,并且将无法进行预检检查。

To solve the issue, a quick solution is to add a fake domain to your hosts file such as local.development and then point to this domain instead of localhost . 要解决此问题,快速解决方案是将伪域添加到您的hosts文件(例如local.development ,然后指向此域而不是localhost You're cross-origin requests should now work. 您现在应该可以使用跨源请求。

Quick Fix For localhost: 快速修复本地主机:

Use Allow-Control-Allow-Origin Chrome Extension and then add localhost in the list with * 使用Allow-Control-Allow-Origin Chrome扩展程序,然后在列表中添加localhost *

Hope this will help. 希望这会有所帮助。

And try using FormData for file Upload.(Angular) 并尝试使用FormData进行文件上传。(Angular)

 let formData:FormData = new FormData();  
 formData.append('Document',file);  

maybe this helps: 也许这有助于:

No 'Access-Control-Allow-Origin' - Node / Apache Port Issue 否'Access-Control-Allow-Origin' - 节点/ Apache端口问题

to wildcard the Access-Control-Allow-Origin just put a "*" instead of the " http://localhost:8888 " origin 通配符Access-Control-Allow-Origin只是放了一个“*”而不是“ http:// localhost:8888 ”来源

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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