首页 > 解决方案 > ASP.NET 4.5 Rest API 在 Unity Android/iOS 构建中的工作,但在 Unity WebGL 构建中因“未知错误”而失败

问题描述

我已经为此搜索了所有可能的论坛,但不知何故没有让我WebGL消费我的ASP.NET 4.5 REST API's.

据我所知,这可能与WebGL要求有关CORS,但即使启用此功能,我也无法让游戏与我的API's

因此,要么是我在其中实现全局CORS设置的方式有问题,ASP.NET要么是其他一些问题正在破坏。需要明确的是,这些 APIAndroid/iOS/Windows builds在编辑器中甚至在编辑器中运行得非常好。

到目前为止我所做的:Microsoft CORS build按照微软相关文档的建议 安装,然后将以下代码添加到WebAPIConfig类中Visual Studio

public static void Register(HttpConfiguration config)
{
    config.SuppressDefaultHostAuthentication();
    config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

    // Web API routes
    config.MapHttpAttributeRoutes();

    ////new code 
    config.EnableCors(new EnableCorsAttribute("*", "*", "*"));

    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}

这也在我的 web.config 中:

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
    <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
  </customHeaders>
</httpProtocol>

我需要这些全局设置,因此我使用"*"文档中指示的包含所有域、方法类型和标头,因为我对我的 API 使用 ASP.NET 令牌身份验证。

这是在 Unity 项目中获取令牌的代码片段(为了清楚起见,这适用于其他平台,只会在 a 中引发错误WebGL build

public IEnumerator login()
{
    string url = API.ROUTEPATH + API.TOKEN;

    WWWForm form = new WWWForm();
    form.AddField("grant_type", "password");
    form.AddField("username", API.APIUSERNAME);
    form.AddField("password", API.APIPASSWORD);

    UnityWebRequest uwr = UnityWebRequest.Post(url, form);
    uwr.SetRequestHeader("Content-Type", "application/json");

    yield return uwr.SendWebRequest();

    try
    {
        if (uwr.isNetworkError)
        {
            Debug.Log(uwr.error);
        }
        else
        {
            APIAuthToken returnauth = JsonUtility.FromJson<APIAuthToken>(uwr.downloadHandler.text);

            if (!string.IsNullOrEmpty(returnauth.access_token))
            {
                API.hasAuth = true;
                API.token = returnauth.access_token;
                Debug.Log(returnauth.access_token);

            }

        }
    }
    catch
    {

    }
}

uwr.error产生以下非常有用的错误:Unknown Error所以我什至不确定它是否CORS相关,这只是我根据我所做的研究得出的最佳猜测,但即使有多种不同的实现,我仍然会遇到相同的错误。因此,如果API's我的 Unity 代码和我的代码没有问题,请忽略ASP.NET代码片段。

标签: asp.netrestunity3dunity-webglunitywebrequest

解决方案


cURL - 一个简单的curl -I <endpoint>curl -X OPTIONS -v <endpoint>可以揭示与 CORS 相关的大量信息。它可以让您设置不同的来源、检查预检响应等等。

“假设您有一个使用 cookie 进行会话管理的后端 API。您的游戏在您自己的域上测试时运行良好,但是一旦您将文件托管在 Kongregate 上,由于您的 API 请求现在是跨域和遵守严格的 CORS 规则。”

这是你的问题吗?

如果设置不正确,双方可能都会拒绝发送 cookie,但这很好,这意味着您可以控制允许将会话 cookie 发送到哪些域。

因此,您可能需要首先将服务器配置为允许乘以来源 ,但请确保根据白名单验证该值,这样您不仅可以将会话 cookie 发送到任何来源域。带有 CORS 中间件(游戏 ID 12345)和以下来源白名单的 Node Express 示例:

 express = require('express')
var cors = require('cors')
var app = express()

var whitelist = ['https://game12345.konggames.com'];
var corsOptions = {
  credentials: true,
  origin: function (origin, callback) {
    if (whitelist.indexOf(origin) !== -1) {
      callback(null, true)
    } else {
      callback(new Error('Not allowed by CORS'))
    }
  }
};

app.use(cors(corsOptions));
app.options('*', cors(corsOptions)); // Enable options for preflight

app.get('/', (req, res) =>  res.send('Hello World!'))
app.listen(8080, () =>  console.log(`Example app listening on port 8080!`))

cURL 命令检查来自白名单数组中来源的 OPTIONS 预检请求的标头:

curl -X OPTIONS -H"Origin: https://game12345.konggames.com" -v http://localhost:8080/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> OPTIONS / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.58.0
> Accept: */*
> Origin: https://game12345.konggames.com
>
< HTTP/1.1 204 No Content
< X-Powered-By: Express
< Access-Control-Allow-Origin: https://game12345.konggames.com
< Vary: Origin, Access-Control-Request-Headers
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
< Content-Length: 0
< Date: Tue, 24 Sep 2019 22:04:08 GMT
< Connection: keep-alive
<
* Connection #0 to host localhost left intact

指示客户端在发出跨域请求时包含 cookie,如果预检响应不包含 Access-Control-Allow-Credentials: true,或者如果您的 Access-Control-Allow-Access 设置为通配符 (*)那么 cookie 将不会被发送,您可能会在浏览器的 Javascript 控制台中看到错误:

Access to XMLHttpRequest at 'https://api.mygamebackend.com' from origin 'https://game54321.konggames.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

Unity 的 UnityWebRequest 和较旧的 WWW 类XMLHttpRequest在后台使用从远程服务器获取数据。由于没有将withCredentials标志设置为 true 的选项,我们必须在初始化我们的应用程序时执行一个非常肮脏的 hack,以便为适当的请求打开它。在您的 WebGL 模板或生成的 index.html 中:

<script>  
   XMLHttpRequest.prototype.originalOpen = XMLHttpRequest.prototype.open;  
   var newOpen = function(_, url) {  
     var original = this.originalOpen.apply(this, arguments);  
     if (url.indexOf('https://api.mygamebackend.com') === 0) {  
       this.withCredentials = true;  
     }  

     return original;  
   }  
   XMLHttpRequest.prototype.open = newOpen;  
 </script>

这段代码覆盖了 XMLHttpRequest 的 open 方法,因此我们可以在需要时有条件地将 withCredentials 设置为 true。一旦这到位,跨域 cookie 应该开始在 Kongregate 托管的 iframe 域和游戏的后端服务器之间工作!


从这里获取的信息

这看起来也不错


推荐阅读