You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity调用本地GraphQL登录Mutation时返回400 Bad Request错误求助

问题:Unity中UnityWebRequest调用GraphQL登录接口返回400错误及JSON解析失败

我用Unity的UnityWebRequest向本地GraphQL服务器发起登录请求,这个登录Mutation在Apollo Client和Postman里都能正常执行,但在Unity里遇到两个问题:

  • HTTP/1.1 400 Bad Request网络错误
  • 服务器返回JSON解析语法错误(Unexpected token %)

已经试过调整查询语句的写法(比如query/mutation大小写),但问题还是存在。

报错信息1

Network error: HTTP/1.1 400 Bad Request
UnityEngine.Debug:LogError (object)
GraphApi/<LoginMutation>d__3:MoveNext () (at Assets/GraphApi.cs:61)
UnityEngine.SetupCoroutine:InvokeMoveNext (System.Collections.IEnumerator,intptr)

报错信息2

Response body: <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>SyntaxError: Unexpected token % in JSON at position 0<br> &nbsp; &nbsp;at JSON.parse (&lt;anonymous&gt;)<br> &nbsp; &nbsp;at createStrictSyntaxError (C:\snapshot\agent\_work\43\s\src\PLF\Exe\Services\GraphQL\NodeJsServer\node_modules\body-parser\lib\types\json.js:160:10)<br> &nbsp; &nbsp;at parse (C:\snapshot\agent\_work\43\s\src\PLF\Exe\Services\GraphQL\NodeJsServer\node_modules\body-parser\lib\types\json.js:83:15)<br> &nbsp; &nbsp;at C:\snapshot\agent\_work\43\s\src\PLF\Exe\Services\GraphQL\NodeJsServer\node_modules\body-parser\lib\read.js:128:18)<br> &nbsp; &nbsp;at AsyncResource.runInAsyncScope (node:async_hooks:203:9)<br> &nbsp; &nbsp;at invokeCallback (C:\snapshot\agent\_work\43\s\src\PLF\Exe\Services\GraphQL\NodeJsServer\node_modules\raw-body\index.js:231:16)<br> &nbsp; &nbsp;at done (C:\snapshot\agent\_work\43\s\src\PLF\Exe\Services\GraphQL\NodeJsServer\node_modules\raw-body\index.js:220:7)<br> &nbsp; &nbsp;at IncomingMessage.onEnd (C:\snapshot\agent\_work\43\s\src\PLF\Exe\Services\GraphQL\NodeJsServer\node_modules\raw-body\index.js:280:7)<br> &nbsp; &nbsp;at IncomingMessage.emit (node:events:525:35)<br> &nbsp; &nbsp;at endReadableNT (node:internal/streams/readable:1358:12)</pre>
</body>
</html>

UnityEngine.Debug:LogError (object)
GraphApi/<LoginMutation>d__3:MoveNext () (at Assets/GraphApi.cs:64)
UnityEngine.SetupCoroutine:InvokeMoveNext (System.Collections.IEnumerator,intptr)

相关C#代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using TMPro;
using System.Net.Http;
using System;
using System.Threading.Tasks;
using static Unity.IO.LowLevel.Unsafe.AsyncReadManagerMetrics;
using static UnityEditor.Progress;
using static UnityEditor.ShaderData;
using System.Drawing;
using Unity.VisualScripting;

public class GraphApi : MonoBehaviour
{
    public TextMeshProUGUI text;
     public class BypassCertificate : CertificateHandler
    {
        protected override bool ValidateCertificate(byte[] certificateData)
        {
            // 跳过证书验证
            return true;
        }
    }
    void Start()
    {
        StartCoroutine(LoginMutation());
    }

    IEnumerator LoginMutation()
    {
        Debug.Log(@"""" == "\"");

        string graphqlEndpoint = "https://notebook65/graphql/";
        string mutation = @"mutation Login {
                   login(username: ""admin"", password: ""xxx"") {
                        token
                        error {
                                 code
                                 description
                              }
                          }
                    } ";

          string jsonRequestBody = "{\"mutation\" : \"" + mutation + "\"}";
          Debug.Log(jsonRequestBody);
          text.text = jsonRequestBody;

          using UnityWebRequest www = UnityWebRequest.Post(graphqlEndpoint, jsonRequestBody);

          //www.SetRequestHeader("Accept", "application/json");
          www.SetRequestHeader("Content-Type", "application/json");

          // 禁用SSL验证
          www.certificateHandler = new BypassCertificate();

          yield return www.SendWebRequest();

          if (www.result != UnityWebRequest.Result.Success)
          {
              Debug.LogError("Network error: " + www.error);
              if (!string.IsNullOrEmpty(www.downloadHandler.text))
              {
                  Debug.LogError("Response body: " + www.downloadHandler.text);
              }
          }
          else
          {
              string responseBody = www.downloadHandler.text;
              Debug.Log("Response body: " + responseBody);
              text.text = responseBody;
          }
      }
  }

解决方案

问题核心是手动拼接JSON时未处理字符串中的特殊字符(换行、引号等),导致生成的JSON格式无效,服务器无法解析;同时UnityWebRequest.Post默认按表单提交处理,与application/json的请求头冲突。

修复步骤及代码示例

using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using TMPro;

public class GraphApi : MonoBehaviour
{
    public TextMeshProUGUI text;

    public class BypassCertificate : CertificateHandler
    {
        protected override bool ValidateCertificate(byte[] certificateData)
        {
            // 跳过证书验证
            return true;
        }
    }

    // 定义序列化类,用于生成合法JSON
    [System.Serializable]
    private class GraphQLRequest
    {
        public string mutation;
    }

    void Start()
    {
        StartCoroutine(LoginMutation());
    }

    IEnumerator LoginMutation()
    {
        string graphqlEndpoint = "https://notebook65/graphql/";
        string mutation = @"mutation Login {
                   login(username: ""admin"", password: ""xxx"") {
                        token
                        error {
                                 code
                                 description
                              }
                          }
                    } ";

        // 通过JsonUtility序列化生成合法JSON,自动处理特殊字符
        GraphQLRequest request = new GraphQLRequest { mutation = mutation };
        string jsonRequestBody = JsonUtility.ToJson(request);
        Debug.Log(jsonRequestBody);
        text.text = jsonRequestBody;

        // 手动构建POST请求,使用原始字节数组传递JSON
        using UnityWebRequest www = new UnityWebRequest(graphqlEndpoint, "POST");
        byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(jsonRequestBody);
        www.uploadHandler = new UploadHandlerRaw(bodyRaw);
        www.downloadHandler = new DownloadHandlerBuffer();

        www.SetRequestHeader("Content-Type", "application/json");
        www.SetRequestHeader("Accept", "application/json");

        // 禁用SSL验证
        www.certificateHandler = new BypassCertificate();

        yield return www.SendWebRequest();

        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.LogError("Network error: " + www.error);
            if (!string.IsNullOrEmpty(www.downloadHandler.text))
            {
                Debug.LogError("Response body: " + www.downloadHandler.text);
            }
        }
        else
        {
            string responseBody = www.downloadHandler.text;
            Debug.Log("Response body: " + responseBody);
            text.text = responseBody;
        }
    }
}

关键修改点

  1. 新增GraphQLRequest类,通过JsonUtility.ToJson生成格式正确的JSON,避免手动拼接的语法错误。
  2. 放弃UnityWebRequest.Post,手动构建POST请求并使用UploadHandlerRaw传递JSON字节数组,避免表单编码与JSON请求头的冲突。
  3. 明确设置Accept请求头,符合GraphQL服务器的响应预期。

内容的提问来源于stack exchange,提问作者lnmr24

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 18:20:55