【问题标题】:Create Json in VB.net from string and use it in WebRequest从字符串在 VB.net 中创建 Json 并在 WebRequest 中使用它
【发布时间】:2020-07-16 09:12:43
【问题描述】:

我正在尝试在 vb.net 中调用 openrouteservice api,因此尝试关注 documentation/examples。该示例显示以下代码作为工作示例:

Sub Main(args As String())
    Dim request = TryCast(System.Net.WebRequest.Create("https://api.openrouteservice.org/v2/directions/driving-car/gpx"), System.Net.HttpWebRequest)

    request.Method = "POST"

    request.Accept = "application/json, application/geo+json, application/gpx+xml, img/png; charset=utf-8"
    request.Headers.Add("Authorization", "xxxxMYKEYxxxx")
    request.Headers.Add("Content-Type", "application/json; charset=utf-8")

    Using writer = New System.IO.StreamWriter(request.GetRequestStream())
        Dim byteArray As Byte() = System.Text.Encoding.UTF8.GetBytes({"coordinates:[[8.681495,49.41461],[8.686507,49.41943],[8.687872,49.420318]]"})
        request.ContentLength = byteArray.Length
        writer.Write(byteArray)
        writer.Close()
    End Using
    Dim responseContent As String
    Using response = TryCast(request.GetResponse(), System.Net.HttpWebResponse)
        Using reader = New System.IO.StreamReader(response.GetResponseStream())
            responseContent = reader.ReadToEnd()
            Console.WriteLine(responseContent.ToString())
        End Using
    End Using
End Sub

示例显示请求正文的内容应该如下:

{"coordinates":[[8.681495,49.41461],[8.686507,49.41943],[8.687872,49.420318]]}

但是在运行示例时出现以下错误:

'The remote server returned an error: (500) Internal Server Error.'

所以我认为请求失败是因为 Json 无效。 我的问题是如何创建一个与上面提供的示例 JSON 相同的 JSON?

【问题讨论】:

    标签: json vb.net rest httpwebrequest


    【解决方案1】:

    API 需要一个 JSON 对象,表示一个双值数组的数组,作为 HttpRequest 的内容,编码为 UTF-8 字符串,作为字节数组发送。

    此集合可以由 .Net 类的 List(Of List(Of Double) 属性类型表示:

    ' Note that JavaScriptSrializer might ignore <JsonProperty>,
    ' so use lower case, since the Web API is case-sensitive
    Friend Class MyObject
        <JsonProperty("coordinates")>
        Public Property coordinates As List(Of List(Of Double))
    End Class
    

    在这之后,我们只需要填写列表:

    Dim myobj = New MyObject() With {
        .Coordinates = New List(Of List(Of Double)) From {
            New List(Of Double)({8.681495, 49.41461}),
            New List(Of Double)({8.686507, 49.41943}),
            New List(Of Double)({8.687872, 49.420318})
        }
    }
    

    并使用Json.Net(通过 NuGet 包管理器安装 NuGet 包)或JavaScriptSerializer(或任何其他可用的 JSON 序列化程序)对其进行序列化:

    JavaScriptSerializer 需要对 System.Web.Extension 的项目引用并导入 System.Web.Script.Serialization

    ' Using Json.Net
    Dim Json As String = JsonConvert.SerializeObject(myobj)
    
    ' Or JavaScriptSerializer
    Dim json = New JavaScriptSerializer().Serialize(myobj)
    

    ► 原代码问题不止一个:

    • webRequest.ContentLength设置太晚:需要在请求发送前设置
    • 用于写入 WebRequest 流的 StreamWriter 会破坏该过程:不需要它,它将在字节写入请求流之前关闭
    • Content-Type 不能使用 Headers 设置,我们必须使用 WebRequest.ContentType 属性
    • 添加 SecurityProtocolType.Tls12 以防此代码在 Windows 7 或 WM 中使用(在 Windows 7 中,默认为 SecurityProtocolType.Ssl3 Or SecurityProtocolType.Tls,因此 TLS1.0,已不再使用, TLS1.2 目前(仍然)是主要参与者)

    修复原代码,使用JavaScriptSerializer序列化请求数据:

    如果您使用 Json.Net,请将 Imports System.Web.Script.Serialization 替换为 Imports Newtonsoft.Json

    Imports System.IO
    Imports System.Text
    Imports System.Web.Script.Serialization
    
    Dim myobj = New MyObject() With {
        .Coordinates = New List(Of List(Of Double)) From {
            New List(Of Double)({8.681495, 49.41461}),
            New List(Of Double)({8.686507, 49.41943}),
            New List(Of Double)({8.687872, 49.420318})
        }
    }
    
    Dim json As String = New JavaScriptSerializer().Serialize(myobj)
    
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
    Dim request = WebRequest.CreateHttp("https://api.openrouteservice.org/v2/directions/driving-car/gpx")
    
    request.Method = "POST"
    request.PreAuthenticate = True
    request.Accept = "application/json, application/geo+json, application/gpx+xml, img/png; charset=utf-8"
    request.Headers.Add("Authorization", "[Your API Key]")
    request.ContentType = "application/json; charset=utf-8"
    
    Dim jsonBytes = Encoding.UTF8.GetBytes(json)
    request.ContentLength = jsonBytes.Length
    Using reqStream = request.GetRequestStream()
        reqStream.Write(jsonBytes, 0, jsonBytes.Length)
    End Using
    
    Dim responseContent As String = String.Empty
    Using response = DirectCast(request.GetResponse(), HttpWebResponse),
        responseStream = response.GetResponseStream(),
        reader = New StreamReader(responseStream)
        responseContent = reader.ReadToEnd()
    End Using
    

    【讨论】:

    • 刚刚又检查了一遍,调用request.getResponse时出现异常:System.Net.Http.HttpRequestException: An error occurred while sending the request. ---&gt; System.IO.IOException: The server returned an invalid or unrecognized response.
    • 是的,您的原始代码中有不止一个错误。我没有修复错误,因为我专注于 JSON 生成。我现在已经发布了整个请求,并修复了所有错误。请参阅有关 JavaScriptSerializer 的添加说明。如果您可以改用 Json.Net,那就更好了。但是这段代码无论如何都可以工作。
    • 这成功了,非常感谢!您是从哪里得知安全协议的?
    • 如果你的意思是ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12,我添加了这个,因为如果你使用的是Window 7(或者你的代码可能会在那里),默认的SSL协议是SecurityProtocolType.Ssl3 Or SecurityProtocolType.Tls,所以有一个请求被拒绝的可能性很大(这个 API 使用 HTTPS,它接受TLS1.0 的可能性很小)。此外,WebRequest.ContentType 无法使用标头设置(出于神秘原因),并且您正在写入错误的 Stream + 微小更改。
    猜你喜欢
    • 1970-01-01
    • 2020-09-29
    • 2013-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-29
    相关资源
    最近更新 更多