WebGL跨域图像无法工作

4

我有一个跨域图像的问题,希望你可以帮忙解决。

这里是具体情况。我有两个域名,例如: - domain1.com - domain2.com

在domain1上,我放了很多html5游戏。这个域名只是游戏的存储库。

Domain2是真正的网站(wordpress网站),用户可以在其上玩托管在domain1上的游戏。为此,我为每个游戏进行了curl请求。

在domain1的nginx配置文件中,我加入了以下代码以启用跨域资源共享:

    location ~* \.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|json|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf|swf|mp3|xml|woff2)$ {
        add_header "Access-Control-Allow-Origin" "*";
        access_log off;
        log_not_found off;
        expires max;
    }

这解决了许多游戏的问题,但仍有一些游戏无法工作,我收到以下js错误:

    Uncaught DOMException: Failed to execute 'texImage2D' on 'WebGLRenderingContext': The cross-origin image at http://domain1.com/html5-games/action/candy-match/images/loadingbarbackground-sheet0.png may not be loaded.
        at GLWrap_.loadTexture (http://domain1.com/html5-games/action/candy-match/c2runtime.js:2618:16)
        at pluginProto.Type.typeProto.loadTextures (http://domain1.com/html5-games/action/candy-match/c2runtime.js:18070:46)
        at pluginProto.Instance.instanceProto.onCreate (http://domain1.com/html5-games/action/candy-match/c2runtime.js:18146:13)
        at Runtime.createInstanceFromInit (http://domain1.com/html5-games/action/candy-match/c2runtime.js:4806:8)
        at Layer.createInitialInstances (http://domain1.com/html5-games/action/candy-match/c2runtime.js:7541:25)
        at Layout.startRunning (http://domain1.com/html5-games/action/candy-match/c2runtime.js:6715:10)
        at Runtime.go_loading_finished (http://domain1.com/html5-games/action/candy-match/c2runtime.js:4067:36)
        at Runtime.go (http://domain1.com/html5-games/action/candy-match/c2runtime.js:3966:9)
        at http://domain1.com/html5-games/action/candy-match/c2runtime.js:4025:60

我在线上进行了一些研究,发现了像这样的文章:

https://webglfundamentals.org/webgl/lessons/webgl-cors-permission.html Drawing images to canvas with img.crossOrigin = "Anonymous" doesn't work

但它们并不是很有帮助。

如果可能的话,我不想修改原始游戏文件。我正在寻找服务器端解决方案。如果没有,你有什么解决我的问题的想法吗?

我的配置中是否存在错误?我是否遗漏了某些内容?

感谢您的帮助。

瓦莱里奥


你是否通过浏览器开发工具检查过,你的域名1服务器是否实际返回了正确的头部信息? - CBroe
嗨@CBroe,显然头部看起来没问题。HTTP/1.1 200 OK 服务器:nginx/1.6.2 日期:2017年9月26日星期二09:33:11 GMT 内容类型:text/html 内容长度:4431 上次修改时间:2017年9月26日星期二08:00:45 GMT 连接:保持连接 ETag:“59ca092d-114f” 接受范围:字节 - Valerio Monti
我的意思是针对这些图片... - CBroe
抱歉@CBroe,这里是我获取图像的标题https://imgur.com/a/huxPq - Valerio Monti
嗯,就CORS头来说,看起来还可以。那可能是代码的问题了。如果不考虑修改代码,那么我认为你可能必须避免在这里使用跨源图像;除非你愿意通过domain1服务器代理它们... - CBroe
1
尝试将访问控制标头设置为实际域名,而不是通配符。此外,可以尝试使用另一个浏览器以获得更详细的错误消息。 - LJᛃ
2个回答

6
游戏需要请求跨域图片。仅仅返回正确的头部不够。如果游戏本身没有通过设置“crossOrigin”属性请求跨域图片,则浏览器即使有正确的头部也不允许使用这些图片。
以下是示例:

const gl = document.createElement("canvas").getContext("webgl");
const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);

loadImage('https://i.imgur.com/ZKMnXce.png', false);
loadImage('https://i.imgur.com/u6VI8xz.jpg', true);

function loadImage(url, crossOrigin) {
  const img = new Image();
  img.onload = () => { upload(img); };
  if (crossOrigin) {
    img.crossOrigin = '';
  }
  img.src = url;
}

function upload(img) {
  // trap for cors error
  try {
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
    log(img.src, "uploaded image");
  } catch (e) {
    log(img.src, e);
  }
}

function log(...args) {
  const elem = document.createElement("pre");
  elem.textContent = [...args].join(' ');
  document.body.appendChild(elem);
}
pre { margin: 0; }

在这里,你可以看到即使第一张图像返回了CORS标头,但是由于没有设置 crossOrigin,它也无法使用。

enter image description here

第二张图片具有相同的标题,但它能够正常工作是因为我们设置了 crossOrigin 属性。

enter image description here

请注意,您也许可以在游戏脚本之前包含类似这样的脚本,以实现CORS支持的一种黑客方式。
(function() {

function isSameOrigin(url) {
  return (new URL(url, window.location.href)).origin === window.location.origin;
}

function needsCORS(url) {
  // not sure all the URLs that should be checked for
  return !isSameOrigin(url) && !url.startsWith("blob:") && !url.startsWith("data:");
}

const srcSetFn = Object.getOwnPropertyDescriptor(HTMLImageElement.prototype, 'src').set; 

Object.defineProperty(HTMLImageElement.prototype, 'src', {
  enumerable: true,
  set: function(url) {
     if (needsCORS(url)) {
       // Set if not already set
       if (this.crossOrigin !== undefined) {
         this.crossOrigin = '';
       }
     } else {
       this.crossOrigin = undefined;
     }
     // Set the original attribute
     srcSetFn.call(this, url);
  },
});

}());

-1

http://webgl-hooman.blogspot.ca/2018/01/cross-origin-image-cannot-be-loaded-in.html

CORS = 跨域资源共享。这是网页请求图像服务器使用图像的一种方式。跨域是Google Chrome内置的安全保护,不允许用户访问本地文件(在这种情况下是您的图像/纹理)。即使在Safari中,您也会收到“操作不安全”的错误。您有几个选择。最简单的方法是将您的WebGL应用程序从诸如IIS或Apache之类的Web服务器运行。另一个选项是在Windows上使用Internet Explorer或Microsoft Edge浏览器打开您的WebGL应用程序。如果您正在使用Mac上的“FireFox”浏览器运行WebGL应用程序,请在HTML中为加载纹理的图像标记添加crossorigin =“anonymous”。但是,如果您使用的是“Windows”操作系统或任何其他浏览器,即使在Mac上也无法正常工作!它仅适用于MAC + Firefox。因此,要么更改您的图像标记为此,要么简单地添加此变量image = document.getElementById(“texImage”); image.crossOrigin =“”; 更多信息,请阅读:https://webglfundamentals.org/webgl/lessons/webgl-cors-permission.html

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接