![](/img/trans.png)
[英]Sending HTTP POST request from SQL Server 2012 or SQL CLR C#
[英]C# SQL Server CLR Request error on functions GET and POST
我按照GitHub 文檔使用 CURL 擴展實現 http 請求,在 SQL Server 2008 R2、Visual Studio 2010 和 .NET 3.5 中工作。
我設法在 Visual Studio 中正確編譯和簽名 .dll,然后在 SQL Server 中創建架構和函數,因為一切正常,我可以從 SQL Server 執行 GET 和 POST,但是,當想要執行 GET 或在 SABA API 上 POST,它會產生一系列錯誤。
執行用戶定義的例程或聚合“XGET”期間發生 .NET Framework 錯誤:System.Net.WebException:基礎連接已關閉:發送時發生意外錯誤。 ---> System.IO.IOException: 從傳輸流接收到意外的 EOF 或 0 字節。 System.IO.IOException: at System.Net.FixedSizeReader.ReadPacket(Byte[] buffer, Int32 offset, Int32 count) at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest) at System .Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest) 在 System.Net.Security.SslState.CheckCompletionBeforatextReceive(ProtocolTokat message, AsyncProtocolRequest asyncRequest) 在 System.Net.Security.SslState.StartSatdBlob(Byte[] 傳入, Int32 計數,AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.ForceAuthattication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest) at System.Net.Security.SslState.ProcessAuthattication(LazyAsyncResult lazyResult) at System.Net.TlsStream.CallProcessAuthattication (對象狀態) 在 System.Threading.ExecutionContext.runTryCode(Object userData) 在 System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode bac koutCode, Object userData) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Net.TlsStream.ProcessAuthattication( LazyAsyncResult 結果)
在 System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size) at System.Net.PooledStream.Write(Byte[] buffer, Int32 offset, Int32 size) at System.Net.ConnectStream.WriteHeaders(Boo ... System.Net.WebException: 在 System.Net.WebCliatt.DownloadDataInternal(Uri address, WebRequest& request) at System.Net.WebCliatt.DownloadString(Uri address) ...
這是大會的代碼
using Microsoft.SqlServer.Server;
using System;
using System.Data.SqlTypes;
using System.Net;
using System.Threading;
public static class Curl
{
[SqlFunction]
[return: SqlFacet(MaxSize = -1)]
public static SqlChars Get(SqlChars H, SqlChars url)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls;
var client = new WebClient();
AddHeader(H, client);
return new SqlChars(
client.DownloadString(
Uri.EscapeUriString(url.ToSqlString().Value)
).ToCharArray());
}
[SqlProcedure]
public static void Post(SqlChars H, SqlChars d, SqlChars url)
{
var client = new WebClient();
AddHeader(H, client);
if (d.IsNull)
throw new ArgumentException("You must specify data that will be sent to the endpoint", "@d");
var response =
client.UploadString(
Uri.EscapeUriString(url.ToSqlString().Value),
d.ToSqlString().Value
);
SqlContext.Pipe.Send("Request is executed. " + response);
}
[SqlProcedure]
public static void PostWithRetry(SqlChars H, SqlChars d, SqlChars url)
{
var client = new WebClient();
AddHeader(H, client);
if (d.IsNull)
throw new ArgumentException("You must specify data that will be sent to the endpoint", "@d");
int i = RETRY_COUNT;
string response = "";
do try
{
response =
client.UploadString(
Uri.EscapeUriString(url.ToSqlString().Value),
d.ToSqlString().Value
);
i = -1;
break;
}
catch (Exception ex)
{
SqlContext.Pipe.Send("Error:\t" + ex.Message + ". Waiting " + DELAY_ON_ERROR + "ms.");
i--;
Thread.Sleep(DELAY_ON_ERROR);
}
while (i > 0);
if (i == -1)
SqlContext.Pipe.Send("Request is executed." + response);
}
static readonly int RETRY_COUNT = 3;
static readonly int DELAY_ON_ERROR = 50;
public static bool IsNullOrWhiteSpace(this string theString)
{
if (theString == null)
{
return false;
}
if (theString.Trim() == string.Empty)
{
return false;
}
return true;
}
private static void AddHeader(SqlChars H, WebClient client)
{
if (!H.IsNull)
{
string header = H.ToString();
if (!IsNullOrWhiteSpace(header))
client.Headers.Add(HttpRequestHeader.UserAgent, header);
}
}
};
這如何在 SQL 查詢中使用
declare @hkey nvarchar(4000) = 'SabaCertificate: 31336132353061666330315E235E756F6E6555E6261536974655E235E656E5F55535E235E536162615E235E24414021463393C69358BE384802BA1BBEAD3B4661862F193021435F7E28A30F7540FE661B9C5F30FDB06C';
declare @endpoint nvarchar(1000) = 'https://libertad-api.sabacloud.com/v1/location?count=10&startPage=1';
select curl.xget(@hkey, @endpoint)
我已經在 PostMan 中對其進行了測試,輸入了 SabaCertificate 的 Header,如果它向我拋出一個結果,但是,當證書不正確時,它也會拋出一個響應並且不顯示。
錯誤請求示例:
{"errorCode":123,"errorMessage":"Invalid or expired Certificate"}
但它也沒有給我證書錯誤的答案,我必須在我的 WebClient 中進行更改才能使其正常工作。
除此之外,我認為證書太大,因為有時我會收到此錯誤:
該標識符以“SabaCertificate:31336132353061666330315E235E756F6E6555E6261536974655E235E656E5F55535E235E536162615E235E24414021463393C69358BE384802BA1BBEAD3B4661862F193021435F7E28A30F7540FE661B9C5F30FDB06C”太長。 最大長度為 128。
代碼中的一個明確問題是您對原始代碼所做的輕微更改。 在您的AddHeader
方法中,您有以下行:
client.Headers.Add(HttpRequestHeader.UserAgent, header);
您需要刪除HttpRequestHeader.UserAgent
因為代碼現在正在創建一個“UserAgent”標頭,其值為您傳入的任何值,即“SabaCertificate: 31336132....”。
您還需要更改您設置的安全協議,因為它們不正確。 你應該試試:
ServicePointManager.SecurityProtocol |= (SecurityProtocolType)3072; // TLS 1.2
由於您通過 SQL Server 2008 R2 使用 .NET 3.5,您不能指定SecurityProtocolType.Tls12
因為該值尚未添加到框架版本 3.5 中的枚舉中,因此您必須使用如上所示的數值。 請記住,執行安全協議的實際能力是底層操作系統的功能,因此舊版本的 Windows/Windows Server 可能不支持 TLS 1.2,或者可能需要更改注冊表設置才能這樣做。 如果您繼續從System.Net.TlsStream
收到類似的錯誤,您將不得不解決這個問題。
此外,以下錯誤:
以“SabaCertificate: 31336...30FDB06C”開頭的標識符太長。 最大長度為 128。
來自用戶錯誤。 “標識符”是 SQL Server 中的項目名稱(對象、登錄名、變量等)。 這意味着當該錯誤發生時,您正在做一些不同的(和錯誤的)事情,但我看不出它是如何來自您的代碼,至少不是Get
方法,因為它與數據庫沒有內部交互。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.