为 post SendAsync 设置 HttpRequestMessage.Content (json) 会导致意外字符错误
Setting HttpRequestMessage.Content (json) for post SendAsync results in Unexpected character error
设置:
(服务器).Net Core 2 API
(客户端) 用 C# 编码的 AWS Lambda 函数(设置必须生成 JWT 的方式)。
使用 JWT 的 IDS3(对于发送请求的方法很重要)
IDS3 和 JWT 部分工作正常。拨打电话并点击 .Net Core 2 API 控制器工作正常。
问题是我收到以下错误:
Unexpected character encountered while parsing value: {. Path '', line 1, position 1.\"]
代码及解释:
StringContent stringContent = new StringContent(eventStr, Encoding.UTF8, "application/json");
using (HttpClient client = new HttpClient()) {
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, myApiURL);
requestMessage.Content = stringContent;
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", jwtToken);
HttpResponseMessage thing = client.SendAsync(requestMessage).Result;
string actualResponse = thing.Content.ReadAsStringAsync().Result;
}
eventStr
是 AWS 传递给函数处理程序的 json 字符串。
actualResponse
包含错误:Unexpected character encountered while parsing value: {. Path '', line 1, position 1.\"]
我检查了正在生成的 StringContent,它绝对正确。
事情的 API 方面发生的事情是发现 JWT 非常正确,控制器构造函数被触发,操作永远不会被触发,表面上是因为数据有效负载(eventStr)不是'正确附加到 HttpRequestMessage
。
API 操作的方法签名:
public async Task<ActionResult> Post([FromBody] string Message)
如果那不是正确的地方,那是什么?
我建议您使用 Flurl 库,它会为您节省很多时间。
因此您可以将代码切换为以下内容(请注意我对某些行进行了注释,您可以根据请求的使用情况删除这些行):
try
{
//Needed if request sent over Https
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//OPTIONAL: set certificates validation, from a static container of global configuration
Flurl.Configure(settings =>
{
settings.HttpClientFactory = new MyHttpClientFactory();
});
var result = await myApiUrl
.WithHeader("Authorization", $"Bearer {jwtToken}")
.PostJsonAsync(requestMessage)
.ReceiveString(); //For response as string
.ReceiveJson<MyClass>(); // to map a json result to an object
}
catch(FlurlHttpException ex)
{
throw ex.InnerException;
}
使用 MyHttpClientFactory class:
public class MyHttpClientFactoryDev : DefaultHttpClientFactory
{
public override HttpMessageHandler CreateMessageHandler()
{
//If you want to validate all certs
return new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyError) => true
};
//If you need to verify certificate signature
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(X509Certificate.CreateFromCertFile("path to cert"));
return handler;
}
}
希望你会发现这有用。
问题不在于 json。
所以 AWS lambda 函数被 AWS 发送了一个匿名类型。基本上只是一个快速松散的对象。
由于 POST,我需要通过 StringContent 变量将其作为字符串发送。但是,如果我序列化它,Core API 控制器会说 "Hey, I know this! It's JSON. Let's deserialize it." 并且确实如此。
鉴于操作需要一个字符串,控制器说 "There are no actions that accept this object I have here. This is a Bad Request."
但是,如果我将其作为纯字符串发送(例如,“{key1:value1”} 而不是“{\”key1\”: \”value1\”}”),键周围没有引号和值,控制器和动作说 "HEY! This is a string. I got this."
那么问题是它在那个时候是无效的 json,有点像 JSON。所以它没有被动作的胆量正确对待。
就目前而言,在没有进一步了解和研究的情况下,解决方法是更改操作签名以期望类型为 Object
的参数,并在方法中专门对其进行反序列化。
虽然这可行,但感觉不是正确的解决方案,因为我现在实质上是打开对任何对象类型的调用,而不是我们真正想要的对象类型。这是有道理的,因为 AWS Lambda 函数被传递了一个匿名类型(即:对象)。
本文介绍了可用于纠正此问题的解决方案类型。缺点是 Core API 并不知道如何处理字符串。作者列出了几种解决方案。我选择实现的是扩展输入格式化程序。我将在这里总结一些过程:
新 class -> RawRequestBodyFormatter : InputFormatter
CTOR -> SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
override Boolean CanRead
override async Task<InputFormatterResult> ReadRequestBodyAsync
检查 context.HttpContext.Request.ContentType
是否包含您的 text/plain
修饰符。
在启动中,添加以下内容:
services.AddMvc(o => o.InputFormatters.Insert(0, new RawRequestBodyFormatter()));
设置:
(服务器).Net Core 2 API
(客户端) 用 C# 编码的 AWS Lambda 函数(设置必须生成 JWT 的方式)。
使用 JWT 的 IDS3(对于发送请求的方法很重要)
IDS3 和 JWT 部分工作正常。拨打电话并点击 .Net Core 2 API 控制器工作正常。
问题是我收到以下错误:
Unexpected character encountered while parsing value: {. Path '', line 1, position 1.\"]
代码及解释:
StringContent stringContent = new StringContent(eventStr, Encoding.UTF8, "application/json");
using (HttpClient client = new HttpClient()) {
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, myApiURL);
requestMessage.Content = stringContent;
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", jwtToken);
HttpResponseMessage thing = client.SendAsync(requestMessage).Result;
string actualResponse = thing.Content.ReadAsStringAsync().Result;
}
eventStr
是 AWS 传递给函数处理程序的 json 字符串。
actualResponse
包含错误:Unexpected character encountered while parsing value: {. Path '', line 1, position 1.\"]
我检查了正在生成的 StringContent,它绝对正确。
事情的 API 方面发生的事情是发现 JWT 非常正确,控制器构造函数被触发,操作永远不会被触发,表面上是因为数据有效负载(eventStr)不是'正确附加到 HttpRequestMessage
。
API 操作的方法签名:
public async Task<ActionResult> Post([FromBody] string Message)
如果那不是正确的地方,那是什么?
我建议您使用 Flurl 库,它会为您节省很多时间。
因此您可以将代码切换为以下内容(请注意我对某些行进行了注释,您可以根据请求的使用情况删除这些行):
try
{
//Needed if request sent over Https
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//OPTIONAL: set certificates validation, from a static container of global configuration
Flurl.Configure(settings =>
{
settings.HttpClientFactory = new MyHttpClientFactory();
});
var result = await myApiUrl
.WithHeader("Authorization", $"Bearer {jwtToken}")
.PostJsonAsync(requestMessage)
.ReceiveString(); //For response as string
.ReceiveJson<MyClass>(); // to map a json result to an object
}
catch(FlurlHttpException ex)
{
throw ex.InnerException;
}
使用 MyHttpClientFactory class:
public class MyHttpClientFactoryDev : DefaultHttpClientFactory
{
public override HttpMessageHandler CreateMessageHandler()
{
//If you want to validate all certs
return new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (sender, certificate, chain, sslPolicyError) => true
};
//If you need to verify certificate signature
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(X509Certificate.CreateFromCertFile("path to cert"));
return handler;
}
}
希望你会发现这有用。
问题不在于 json。
所以 AWS lambda 函数被 AWS 发送了一个匿名类型。基本上只是一个快速松散的对象。
由于 POST,我需要通过 StringContent 变量将其作为字符串发送。但是,如果我序列化它,Core API 控制器会说 "Hey, I know this! It's JSON. Let's deserialize it." 并且确实如此。
鉴于操作需要一个字符串,控制器说 "There are no actions that accept this object I have here. This is a Bad Request."
但是,如果我将其作为纯字符串发送(例如,“{key1:value1”} 而不是“{\”key1\”: \”value1\”}”),键周围没有引号和值,控制器和动作说 "HEY! This is a string. I got this."
那么问题是它在那个时候是无效的 json,有点像 JSON。所以它没有被动作的胆量正确对待。
就目前而言,在没有进一步了解和研究的情况下,解决方法是更改操作签名以期望类型为 Object
的参数,并在方法中专门对其进行反序列化。
虽然这可行,但感觉不是正确的解决方案,因为我现在实质上是打开对任何对象类型的调用,而不是我们真正想要的对象类型。这是有道理的,因为 AWS Lambda 函数被传递了一个匿名类型(即:对象)。
本文介绍了可用于纠正此问题的解决方案类型。缺点是 Core API 并不知道如何处理字符串。作者列出了几种解决方案。我选择实现的是扩展输入格式化程序。我将在这里总结一些过程:
新 class -> RawRequestBodyFormatter : InputFormatter
CTOR -> SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
override Boolean CanRead
override async Task<InputFormatterResult> ReadRequestBodyAsync
检查 context.HttpContext.Request.ContentType
是否包含您的 text/plain
修饰符。
在启动中,添加以下内容:
services.AddMvc(o => o.InputFormatters.Insert(0, new RawRequestBodyFormatter()));