在逻辑应用中支持非 Unicode 字符编码Support non-Unicode character encoding in Logic Apps

处理文本有效负载时,Azure 逻辑应用会推断以 Unicode 格式(如 UTF-8)编码的文本。When you work with text payloads, Azure Logic Apps infers the text is encoded in a Unicode format, such as UTF-8. 在工作流中接收、发送或处理使用不同编码的字符时,可能会遇到问题。You might have problems receiving, sending, or processing characters with different encodings in your workflow. 例如,使用不支持 Unicode 的旧系统时,平面文件中可能会出现损坏的字符。For example, you might get corrupted characters in flat files when working with legacy systems that don't support Unicode.

若要处理使用其他字符编码的文本,请将 base64 编码应用于非 Unicode 有效负载。To work with text that has other character encoding, apply base64 encoding to the non-Unicode payload. 此步骤可防止逻辑应用假定文本采用 UTF-8 格式。This step prevents Logic Apps from assuming the text is in UTF-8 format. 然后,可以使用 Azure Functions 将所有 .NET 支持编码转换为 UTF-8 格式。You can then convert any .NET-supported encoding to UTF-8 using Azure Functions.

此解决方案适用于多租户和单租户工作流。This solution works with both multi-tenant and single-tenant workflows. 你还可以将此解决方案用于 AS2 连接器You can also use this solution with the AS2 connector.

转换有效负载编码Convert payload encoding

首先,检查触发器能否正确识别内容类型。First, check that your trigger can correctly identify the content type. 此步骤可确保逻辑应用不再假定文本是 UTF-8 格式。This step ensures that Logic Apps no longer assumes the text is UTF-8.

对于设置为“推断内容类型”的触发器,选择“否”。For triggers with the setting Infer Content Type, choose No. 如果触发器没有此选项,则根据传入消息设置内容类型。If your trigger doesn't have this option, the content type is set by the incoming message.

如果对 text/plain 内容使用 HTTP 请求触发器,则必须在调用的 Content-Type 标头中设置 charset 参数。If you're using the HTTP request trigger for text/plain content, you must set the charset parameter in the Content-Type header of the call. 如果未设置 charset 参数,或参数与有效负载的编码格式不匹配,则字符可能会被损坏。Characters might become corrupted if you don't set the charset parameter, or the parameter doesn't match the payload's encoding format. 有关详细信息,请参阅如何处理 text/plain 内容类型For more information, see how to handle the text/plain content type.

例如,使用正确的 charset 参数设置 Content-Type 标头时,HTTP 触发器会将传入内容转换为 UTF-8 格式:For example, the HTTP trigger converts the incoming content to UTF-8 when the Content-Type header is set with the correct charset parameter:

{
    "headers": {
        <...>
        "Content-Type": "text/plain; charset=windows-1250"
        },
        "body": "non UTF-8 text content"
}

如果将 Content-Type 标头设置为 application/octet-stream,则还可能收到非 UTF-8 字符。If you set the Content-Type header to application/octet-stream, you also might receive characters that aren't UTF-8. 有关详细信息,请参阅如何处理 application/octet-stream 内容类型For more information, see how to handle the application/octet-stream content type.

对内容使用 Base64 编码Base64 encode content

在对内容使用 base64 编码之前,请确保已将文本转换为 UTF-8 格式Before you base64 encode content, make sure you've converted the text to UTF-8. 如果在将文本转换为 UTF-8 格式之前使用 base64 解码将内容转换为字符串,则字符可能会被损坏。If you base64 decode the content to a string before converting the text to UTF-8, characters might return corrupted.

接下来,将所有 .NET 支持编码转换为其他 .NET 支持编码。Next, convert any .NET-supported encoding to another .NET-supported encoding. 请参阅 Azure Functions 代码示例.NET 代码示例Review the Azure Functions code example or the .NET code example:

提示

对于单租户逻辑应用,可以通过在本地运行转换函数,提高性能,减少延迟。For single-tenant logic apps, you can improve performance and decrease latency by locally running the conversion function.

Azure Functions 版本Azure Functions version

以下示例适用于 Azure Functions 版本 2:The following example is for Azure Functions version 2:

using System;
using System.IO;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.WebJobs.Host;
using Newtonsoft.Json;

public static class ConversionFunctionv2 {
  [FunctionName("ConversionFunctionv2")]
  public static IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, TraceWriter log) {
    log.Info("C# HTTP trigger function processing a request.");

    Encoding inputEncoding = null;

    string requestBody = new StreamReader(req.Body).ReadToEnd();
    dynamic data = JsonConvert.DeserializeObject(requestBody);

    if (data == null || data.text == null || data.encodingInput == null || data.encodingOutput == null) {
      return new BadRequestObjectResult("Please pass text/encodingOutput properties in the input JSON object.");
    }

    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

    try {
      string encodingInput = data.encodingInput.Value;
      inputEncoding = Encoding.GetEncoding(name: encodingInput);
    } catch (ArgumentException) {
      return new BadRequestObjectResult($"Input character set value '{data.encodingInput.Value}' is not supported. Supported values are listed at https://msdn.microsoft.com/library/system.text.encoding(v=vs.110).aspx.");
    }

    Encoding encodingOutput = null;
    try {
      string outputEncoding = data.encodingOutput.Value;
      encodingOutput = Encoding.GetEncoding(outputEncoding);
    } catch (ArgumentException) {
      return new BadRequestObjectResult($"Output character set value '{data.encodingOutput.Value}' is not supported. Supported values are listed at https://msdn.microsoft.com/library/system.text.encoding(v=vs.110).aspx.");
    }

    return (ActionResult) new JsonResult(
      value: new {
        text = Convert.ToBase64String(
          Encoding.Convert(
            srcEncoding: inputEncoding,
            dstEncoding: encodingOutput,
            bytes: Convert.FromBase64String((string) data.text)))
      });
  }
}

.NET 版本.NET version

以下示例适用于 .NET Standard 和 Azure Functions 版本 2:The following example is for use with .NET standard and Azure Functions version 2:

    using System;
    using System.IO;
    using System.Text;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Extensions.Http;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Azure.WebJobs.Host;
    using Newtonsoft.Json;

    public static class ConversionFunctionNET
    {
        [FunctionName("ConversionFunctionNET")]
        public static IActionResult Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]HttpRequest req, TraceWriter log)
        {
            log.Info("C# HTTP trigger function processing a request.");

            Encoding inputEncoding = null;

            string requestBody = new StreamReader(req.Body).ReadToEnd();
            dynamic data = JsonConvert.DeserializeObject(requestBody);

            if (data == null || data.text == null || data.encodingInput == null || data.encodingOutput == null)
            {
                return new BadRequestObjectResult("Please pass text/encodingOutput properties in the input JSON object.");
            }

            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

            try
            {
                string encodingInput = data.encodingInput.Value;
                inputEncoding = Encoding.GetEncoding(name: encodingInput);
            }
            catch (ArgumentException)
            {
                return new BadRequestObjectResult($"Input character set value '{data.encodingInput.Value}' is not supported. Supported values are listed at https://msdn.microsoft.com/library/system.text.encoding(v=vs.110).aspx.");
            }

            Encoding encodingOutput = null;
            try
            {
                string outputEncoding = data.encodingOutput.Value;
                encodingOutput = Encoding.GetEncoding(outputEncoding);
            }
            catch (ArgumentException)
            {
                return new BadRequestObjectResult($"Output character set value '{data.encodingOutput.Value}' is not supported. Supported values are listed at https://msdn.microsoft.com/library/system.text.encoding(v=vs.110).aspx.");
            }

            return (ActionResult)new JsonResult(
                value: new
                {
                    text = Convert.ToBase64String(
                        Encoding.Convert(
                            srcEncoding: inputEncoding,
                            dstEncoding: encodingOutput,
                            bytes: Convert.FromBase64String((string)data.text)))
                });
        }
    }

使用以上相同的概念,还可以在工作流中发送非 Unicode 有效负载Using these same concepts, you can also send a non-Unicode payload from your workflow.

示例有效负载转换Sample payload conversions

在此示例中,base64 编码的示例输入字符串是个人名称 Héloïse,其中包含重音字符。In this example, the base64-encoded sample input string is a personal name, Héloïse, that contains accented characters.

输入示例:Example input:

{  
    "text": "SMOpbG/Dr3Nl",
    "encodingInput": "utf-8",
    "encodingOutput": "windows-1252"
}

示例输出:Example output:

{
    "text": "U01PcGJHL0RyM05s"
}

发送非 Unicode 有效负载Send non-Unicode payload

如果需要从工作流发送非 Unicode 有效负载,请反向执行将有效负载转换为 UTF-8 格式的步骤。If you need to send a non-Unicode payload from your workflow, do the steps for converting the payload to UTF-8 in reverse. 让文本在系统中使用尽可能长的 UTF-8 格式。Keep the text in UTF-8 as long as possible within your system. 接下来,使用相同的函数将 base64 编码 UTF-8 字符转换为所需编码字符。Next, use the same function to convert the base64-encoded UTF-8 characters to the required encoding. 然后,将 base64 解码应用于文本,并发送有效负载。Then, apply base64 decoding to the text, and send your payload.

转换 AS2 的有效负载Convert payloads for AS2

你还可以将此解决方案用于 AS2 v2 连接器中的非 Unicode 有效负载。You can also use this solution with non-Unicode payloads in the AS2 v2 connector. 如果不将传递给 AS2 的有效负载转换为 UTF-8 格式,则可能遇到有效负载转译问题。If you don't convert payloads that you pass to AS2 to UTF-8, you might experience problems with the payload interpretation. 这些问题可能会导致合作伙伴之间的 MIC 哈希代码因误转译的字符而不一致。These problems might result in a mismatch with the MIC hash between the partners because of misinterpreted characters.

后续步骤Next steps