Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
489 views
in Technique[技术] by (71.8m points)

extjs form.submit failed due to "accessing a cross-origin frame"

In my extjs6 project I am uploading a file to my webapi. (using form... fileuploadfield) The file gets successfully uploaded and it is supposed to return a simple string list however even though the file gets uploaded properly, in my controller it ALWAYS returns FAILURE on form.submit. Reason..."Blocked a frame with origin "http://localhost:57007" from accessing a cross-origin frame."

I believe I read somewhere that when I do form.submit it creates some kind of frame that causes the cross origin.

Normally I wouldn't care if it always returns failed because the job is still getting done... but I want to return something which wont work if it fails. Can someone help me with a SECURE way of doing this?

PANEL

                    xtype: 'form',
                fileUpload: true, //(1)
                width: 500,
                frame: true,
                title: 'Client Recap Upload Form',
                bodyPadding: '10 10 10 10',
                margin: '10px 10px 10px 10px',
                standardSubmit: false,
                defaults: {
                    anchor: '100%',
                    allowBlank: false,
                    msgTarget: 'side',
                    labelWidth: 50
                },
                items: [{
                    xtype: 'fileuploadfield',
                    emptyText: 'Select a file',
                    fieldLabel: 'Filename',
                    name: 'file',
                    buttonText: 'Choose a file'
                }],
                buttons: [
                    {
                        text: 'Upload',
                        listeners: {
                            click: 'onButtonFileUpload'
                        }
                    }
                ]

CONTROLLER

    onUploadClientRecap: function (field, e, options, mid) {

    var me = this;

    if (field.up('form').getForm().isValid()) {
        field.up('form').getForm().submit({
            url: ExtApplication4.util.GlobalVar.urlTM_UploadClientRecap + mid,
            waitMsg: 'Uploading your file...',
            success: function (form, o)
            {
                Ext.Msg.show({
                    title: 'Result',
                    msg: o.response.responseText,//.result.result,
                    buttons: Ext.Msg.OK,
                    icon: Ext.Msg.INFO
                });
            },
            failure: function (form, o)
            {
                debugger;
                Ext.Msg.show({
                    title: 'Result',
                    msg: 'File Uploaded...',
                    buttons: Ext.Msg.OK,
                    icon: Ext.Msg.INFO
                });
            }
        });
    }
},

WEB API

        [Route("api/tradematch/UploadClientRecap/{mid}")]
    [HttpPost]
    public List<string> UploadClientRecap(HttpRequestMessage request, int mid)
    {
        HttpContext context = HttpContext.Current;
        HttpPostedFile postedFile = context.Request.Files["file"];

        return _repo.UploadClientRecap(postedFile, mid);
    }

in my webapi I am also running this code in my application_beginrequest

        protected void Application_BeginRequest(object sender, EventArgs e)
    {
        string[] allowedOrigin = new string[5];
        allowedOrigin[0] = "http://localhost:57007";
        allowedOrigin[1] = "http://x.com";
        allowedOrigin[2] = "https://x.com";
        allowedOrigin[3] = "https://www.p.com";
        allowedOrigin[4] = "http://www.p.com";

        var origin = HttpContext.Current.Request.Headers["Origin"];
        if (origin != null && allowedOrigin.Contains(origin))
        {
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", origin);

            if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
            {
                HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization, X-Requested-With");
                HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
                HttpContext.Current.Response.End();
            }
        }

trying new webapi to return redirect

        [Route("api/tradematch/UploadClientRecap/{mid}")]
    [HttpPost]
    public HttpResponseMessage UploadClientRecap(HttpRequestMessage request, int mid)
    {
        HttpContext context = HttpContext.Current;
        HttpPostedFile postedFile = context.Request.Files["file"];

        var response = Request.CreateResponse(HttpStatusCode.Moved);
        response.Headers.Location = new Uri("http://www.google.com/" + "&output=crudeOil");
        return response;

        //return _repo.UploadClientRecap(postedFile, mid);
    }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The upload (POST request) of the file is not subject to CORS; however, accessing the body of the iframe (whose context is currently a cross-domain origin) IS certainly subject to it, and is where the cross-domain issue is probably occurring (I've seen this many times).

One way I've circumvented this is to employ an approach similar to what this jquery plugin does: https://github.com/blueimp/jQuery-File-Upload/wiki/Cross-domain-uploads#cross-site-iframe-transport-uploads

In short, in your upload-handling code, you redirect to your client-side app, and pass along the desired data that you wish to be available as a result of the upload in the querystring (e.g., upload time, file name, etc). Then, in your client-side app, create a simple redirect page that will handle the incoming querystring and process it appropriately.

The reason all of this works is that content of the iframe will be ultimately served from the same domain as the request, once the redirect has occurred:

iframe src = cross-domain url

=> POST upload
=> Process upload
=> Redirect response to same domain as original client app

iframe src = original requesting client

Because of this, you can successfully read the content via JS without stepping on the cross-domain policies of iframes.

Here's a very basic example of what your upload code (in Node) might look like to create the redirect:

app.post('/api/photo', function(req, res) {
    if (done == true) {
        var params = {
            sometext: "I am some text",
            success: true,
            msg: 'The upload was successful',
            filename: 'Avatar.png'
        };

        res.redirect('http://myapp.com/results.html?data=' + JSON.stringify(params));
    }
});

And then, your redirect file to handle the response:

<html>
    <head>
        <meta charset="utf-8">
        <title>Cross-Domain Upload Redirect Page</title>
    </head>
    <body>
        <script>
            // strip off "?data="...
            var data = window.location.search.slice(6),
                decodedJSON = decodeURIComponent(data);
            // set JSON string into innerText and textContent 
            // so Ext.data.Connection can treat it
            // the same as regular iframe uploads
            document.body.innerText=document.body.textContent=decodedJSON;
    </script>
</body>


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...