"污染的画布可能无法加载" WebGL纹理的跨域问题

时间:2015-06-19 19:32:37

标签: google-chrome gwt libgdx html5-canvas webgl

我在过去48小时内学到了很多关于跨域政策的知识,但显然还不够。

继续this问题。我的HTML5游戏支持Facebook登录。我试图下载人物朋友的个人资料照片。在我的游戏的HTML5版本中,我在Chrome中收到以下错误。

  

detailMessage:" com.google.gwt.core.client.JavaScriptException:   (SecurityError)↵stack:错误:无法执行' texImage2D'上   ' WebGLRenderingContext':可能无法加载受污染的画布。

据我了解,出现此错误是因为我尝试从其他域加载图片,但这可以使用 Access-Control-Allow-Origin 标头解决,详见this问题。

我尝试下载的网址是

https://graph.facebook.com/1387819034852828/picture?width=150&height=150

查看Chrome中的网络标签我可以看到它具有所需的 access-control-allow-origin 标头,并以302重定向到新网址进行响应。该URL有所不同,我想这取决于负载平衡,但这是一个示例URL。

https://fbcdn-profile-a.akamaihd.net/hprofile-ak-xap1/v/t1.0-1/c0.0.160.160/p160x160/11046398_1413754142259317_606640341449680402_n.jpg?oh=6738b578bc134ff207679c832ecd5fe5&oe=562F72A4&gda=1445979187_2b0bf0ad3272047d64c7bfc2dbc09a29

此网址还包含 access-control-allow-origin 标头。所以我不明白为什么会失败。

作为Facebook,以及成千上万的应用,游戏和网站显示用户个人资料图片的事实,我认为这是可能的。我知道我可以通过自己的服务器反弹,但我不确定为什么我应该这样做。

答案

我最终使用以下代码在libgdx中进行跨域映像加载(这非常hacky,我确信可以改进)。我还没有设法使用AssetDownloader。我希望最终能够解决这个问题。

public void downloadPixmap(final String url, final DownloadPixmapResponse response) {
    final RootPanel root = RootPanel.get("embed-html");
    final Image img = new Image(url);
    img.getElement().setAttribute("crossOrigin", "anonymous");
    img.addLoadHandler(new LoadHandler() {

        @Override
        public void onLoad(LoadEvent event) {
            HtmlLauncher.application.getPreloader().images.put(url, ImageElement.as(img.getElement()));
            response.downloadComplete(new Pixmap(Gdx.files.internal(url)));
            root.remove(img);
        }
    });
    root.add(img);
}

interface DownloadPixmapResponse {
    void downloadComplete(Pixmap pixmap);

    void downloadFailed(Throwable e);
}

3 个答案:

答案 0 :(得分:15)

您在申请之前是否在img上设置了crossOrigin属性?

var img = new Image();
img.crossOrigin = "anonymous";
img.src = "https://graph.facebook.com/1387819034852828/picture?width=150&height=150"; 
当问到这个问题时,它正在为我工​​作。遗憾的是,上面的网址不再指向任何内容,因此我在下面的示例中对其进行了更改



var img = new Image();
img.crossOrigin = "anonymous";   // COMMENT OUT TO SEE IT FAIL
img.onload = uploadTex;
img.src = "https://i.imgur.com/ZKMnXce.png"; 

function uploadTex() {
  var gl = document.createElement("canvas").getContext("webgl");
  var tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);
  try {
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
    log("DONE: ", gl.getError());
  } catch (e) {
    log("FAILED to use image because of security:", e);
  }
}

function log() {
  var div = document.createElement("div");
  div.innerHTML = Array.prototype.join.call(arguments, " ");
  document.body.appendChild(div);
}

<body></body>
&#13;
&#13;
&#13;

如何检查您是否收到标题

打开您的devtools,选择网络选项卡,重新加载页面,选择有问题的图像,查看REQUEST标头和RESPONSE标头。

enter image description here

请求应显示您的浏览器发送了Origin:标题

回复应显示收到

Access-Control-Allow-Methods: GET, OPTIONS, ...
Access-Control-Allow-Origin: *

注意,响应和请求必须显示上面的条目。如果请求丢失Origin:,那么您没有设置img.crossOrigin,即使响应显示确定,浏览器也不会让您使用该图片。

如果您的请求具有Origin:标头,并且响应没有其他标头,则该服务器未授予使用该图像显示它的权限。换句话说,它可以在图像标签中工作,你可以将它绘制到画布上,但你不能在WebGL中使用它,你绘制的任何2d画布都会被污染,toDataURL和{{1将停止工作

答案 1 :(得分:0)

您可以对纹理进行base64编码。

答案 2 :(得分:0)

这是您在本地开发时遇到的典型跨域问题。

我使用python的简单服务器作为快速解决方案。

导航到终端中的目录,然后键入:

 $ python -m SimpleHTTPServer

你会得到

Serving HTTP on 0.0.0.0 port 8000 ...

所以转到0.0.0.0:8000/并且您应该看到问题已解决。