【问题标题】:extjs form.submit failed due to "accessing a cross-origin frame"extjs form.submit 由于“访问跨域框架”而失败
【发布时间】:2020-04-25 01:36:19
【问题描述】:

在我的 extjs6 项目中,我将文件上传到我的 webapi。 (使用表单... fileuploadfield)文件被成功上传,它应该返回一个简单的字符串列表,但是即使文件被正确上传,在我的控制器中它总是在form.submit上返回FAILURE。原因...“阻止了来源为“http://localhost:57007”的框架访问跨域框架。”

我相信我在某处读到过,当我执行 form.submit 时,它会创建某种导致交叉原点的框架。

通常我不在乎它是否总是返回失败,因为工作仍在完成......但我想返回一些如果失败则无法工作的东西。有人可以帮助我以安全的方式执行此操作吗?

面板

                    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'
                        }
                    }
                ]

控制器

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

网页接口

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

在我的 webapi 中,我也在我的 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();
            }
        }

尝试新的 webapi 返回重定向

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

【问题讨论】:

  • 您将文件提交到哪里?一般的解决方案是通过发送适当的 http 标头来明确允许相关域之间的 CORS,但是从您的 sn-ps 无法给出任何具体建议...
  • 会不会是您的前端运行在与您的 api 不同的端口上?您可以使用反向代理使它们在同一来源下可用 - 或者像 Mastacheata 之前所说的那样启用 CORS,更多信息在这里:developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
  • @Mastacheata 我刚刚更新了我的代码以向您展示 webapi。这是否为您提供了所需的信息?
  • @devbnz web api在本地1台pc上发布,前端在diff pc上发布,所以我确定它们是不同的。
  • 我还添加了我在 Application_beginRequest 上运行的代码

标签: extjs cross-domain form-submit


【解决方案1】:

文件的上传(POST请求)不受CORS约束;但是,访问 iframe 的主体(其上下文当前是跨域起源)肯定会受到它的影响,并且可能会发生跨域问题(我已经看过很多次了)。

我绕过这个的一种方法是采用类似于这个 jquery 插件所做的方法:https://github.com/blueimp/jQuery-File-Upload/wiki/Cross-domain-uploads#cross-site-iframe-transport-uploads

简而言之,在您的上传处理代码中,您重定向到您的客户端应用程序,并在查询字符串中传递您希望作为上传结果可用的所需数据(例如,上传时间、文件名称等)。然后,在您的客户端应用程序中,创建一个简单的重定向页面,该页面将处理传入的查询字符串并进行适当的处​​理。

所有这些工作的原因是,一旦发生重定向,iframe 的内容最终将来自与请求相同的域:

iframe src = cross-domain url

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

iframe src = original requesting client

正因为如此,你可以通过JS成功读取内容,而不需要踩到iframe的跨域策略。

这是一个非常基本的示例,说明您的上传代码(在 Node 中)可能看起来像创建重定向:

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

然后,你的重定向文件来处理响应:

<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>

【讨论】:

  • 我正在努力理解这一点,但我对其中一些内容很陌生。从创建重定向的帖子开头开始,您在节点中说明了这一点,我该怎么做?它在我的前端还是在我的 webapi 中?我的前端是一个javascript框架EXTJS,前端api是c#
  • 重定向将发生在处理上传的地方;在这种情况下,在您的应用程序服务器代码中。
  • 我更改了 webapi 代码以返回重定向,但我不确定如何在前端实际处理它。我收到错误,在服务器上找不到请求的 url 代码。很可能是因为我只是编造的。你有一个如何在 extjs 或 javascript 中处理重定向的例子吗?
  • 不确定这是否重要,但这个项目是一个单页应用程序。我认为这意味着我只会使用一个主要网址。因此,即使这种方法正在加载页面,我希望它返回到它开始的页面......在这种情况下是localhost:57007/Sencha/index.html。我尝试返回 response.Headers.Location = new Uri("localhost:57007/Sencha/index.html/?output=fakeparameter"); return response; 但我收到错误 404 not found
  • 如果我只返回这个... Uri("localhost:57007/Sencha/index.html/.. 我收到错误您正在尝试解码无效的 JSON 字符串
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-04
  • 2015-07-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多