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

D365 X++服务端调用外部REST API及报错代码修复

Dynamics 365 F&O X++调用外部API修复方案(解决Bad Request错误)

原代码问题分析

导致Bad Request错误的核心问题如下:

  • Content-Type配置错误:发送JSON格式请求体却设置为text/html,服务端无法解析请求内容
  • 请求头部格式无效:"Pass Owner Id"和"GSTIN"仅声明了头部键名,未设置对应值,且头部名称包含空格不符合HTTP规范
  • Response实例初始化错误:直接new System.Net.HttpWebResponse()属于无效操作,响应实例应由request.GetResponse()返回
  • 资源释放不严谨:异常场景下流和响应对象未被正确关闭,易引发资源泄漏
  • 存在大量未使用的冗余变量,增加代码复杂度

修复后的HttpWebRequest版本代码

public static void main(Args _args)
{
    str destinationUrl = "https://xyz.com/api/your-endpoint"; // 替换为实际接口地址
    str requestJson = '{"param1":"value1","param2":"value2"}'; // 替换为实际JSON请求体
    str responseJson;
    System.Net.HttpWebRequest request;
    System.Net.HttpWebResponse response;
    System.Byte[] bytes;
    System.Text.Encoding utf8;
    System.IO.Stream requestStream, responseStream;
    System.IO.StreamReader streamReader;
    System.Exception ex;
    System.Net.WebHeaderCollection httpHeader;

    try
    {
        new InteropPermission(InteropKind::ClrInterop).assert();
        
        httpHeader = new System.Net.WebHeaderCollection();
        request = System.Net.WebRequest::Create(destinationUrl);
        utf8 = System.Text.Encoding::get_UTF8();
        bytes = utf8.GetBytes(requestJson);

        // 设置请求方法
        request.set_Method("POST");
        // 修正Content-Type为JSON格式
        httpHeader.Add("Content-Type: application/json; charset=utf-8");
        // 规范自定义头部格式并补充值(替换为实际业务值)
        httpHeader.Add("Pass-Owner-Id: your-owner-id");
        httpHeader.Add("GSTIN: your-gstin-value");
        
        request.set_Headers(httpHeader);
        request.set_ContentLength(bytes.get_Length());

        // 写入并关闭请求体流
        requestStream = request.GetRequestStream();
        requestStream.Write(bytes, 0, bytes.get_Length());
        requestStream.Flush();
        requestStream.Close();

        // 获取响应并读取内容
        response = request.GetResponse();
        responseStream = response.GetResponseStream();
        streamReader = new System.IO.StreamReader(responseStream);
        responseJson = streamReader.ReadToEnd();

        info(strFmt("响应结果: %1", responseJson));
    }
    catch (Exception::CLRError)
    {
        ex = CLRInterop::getLastException().GetBaseException();
        error(strFmt("调用失败: %1", ex.get_Message()));
    }
    finally
    {
        // 确保所有资源被正确释放
        if (streamReader != null) streamReader.Close();
        if (responseStream != null) responseStream.Close();
        if (response != null) response.Close();
        CodeAccessPermission::revertAssert();
    }
}

关键修复点说明

  • Content-Type修正:将text/html改为application/json,明确告知服务端请求体为JSON格式,这是解决Bad Request的核心修复项
  • 自定义头部规范:移除头部名称中的空格(改为Pass-Owner-Id格式),并补充对应业务值,符合HTTP头部键: 值的标准格式
  • 资源释放优化:使用finally块确保流和响应对象无论是否异常都会被关闭,避免资源泄漏
  • Response实例修正:删除无效的new System.Net.HttpWebResponse(),由request.GetResponse()返回合法的响应实例
  • 冗余变量清理:删除未使用的变量,简化代码结构

推荐的现代方案:使用HttpClient

HttpWebRequest属于.NET旧版API,Dynamics 365 F&O中推荐使用System.Net.Http.HttpClient,代码更简洁且自带连接池优化:

public static void main(Args _args)
{
    str destinationUrl = "https://xyz.com/api/your-endpoint";
    str requestJson = '{"param1":"value1","param2":"value2"}';
    str responseJson;
    System.Net.Http.HttpClient httpClient;
    System.Net.Http.StringContent content;
    System.Net.Http.HttpResponseMessage response;
    System.Exception ex;

    try
    {
        new InteropPermission(InteropKind::ClrInterop).assert();
        
        httpClient = new System.Net.Http.HttpClient();
        // 添加自定义头部
        httpClient.DefaultRequestHeaders.Add("Pass-Owner-Id", "your-owner-id");
        httpClient.DefaultRequestHeaders.Add("GSTIN", "your-gstin-value");
        
        // 创建JSON请求内容
        content = new System.Net.Http.StringContent(requestJson, System.Text.Encoding::get_UTF8(), "application/json");
        // 发送POST请求并同步获取结果
        response = httpClient.PostAsync(destinationUrl, content).Result;
        
        // 校验请求状态
        if (response.IsSuccessStatusCode)
        {
            responseJson = response.Content.ReadAsStringAsync().Result;
            info(strFmt("响应结果: %1", responseJson));
        }
        else
        {
            error(strFmt("请求失败,状态码: %1,原因: %2", response.StatusCode.ToString(), response.ReasonPhrase));
        }
    }
    catch (Exception::CLRError)
    {
        ex = CLRInterop::getLastException().GetBaseException();
        error(strFmt("调用异常: %1", ex.get_Message()));
    }
    finally
    {
        if (httpClient != null) httpClient.Dispose();
        CodeAccessPermission::revertAssert();
    }
}

额外注意事项

  • 需确保Dynamics 365环境已配置出站网络规则,允许访问目标域名(在LCS环境管理的网络配置中添加)
  • 若目标API需要身份认证(如Bearer Token),需在头部添加Authorization: Bearer {your-token}
  • 生产环境中若处理高并发请求,建议复用HttpClient实例而非每次创建,避免连接耗尽

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 01:49:55