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

*爱你&永不变心* 提交于 2020-04-28 20:45:29

问题


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);
    }

回答1:


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>



来源:https://stackoverflow.com/questions/45512739/extjs-form-submit-failed-due-to-accessing-a-cross-origin-frame

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!