UnityWebRequest and/or HttpWebRequest 使用 PUT 在 Android 上给出 403
UnityWebRequest and/or HttpWebRequest give 403 on Android with PUT
(( 我也在 Unity Answers 和 GameDev 上 post 编辑了这个但是 x-post 在这里以防任何 C# 网络负责人指出任何明显的错误我的 HttpWebRequest 代码...))
我正在尝试 post 通过他们的 SDK 将通过我的游戏捕获的图像发送到 Facebook,并且由于它需要 URI,我编写了一个简单的 AWS Lambda 函数来获取字节数组并将其上传到AWS 存储桶。 AWS 函数接受一个调用,然后 returns a URL 调用 PUT 来处理图像数据...
所以想法是,如果响应是 200,请使用 URL 到 post 到 FB。
但是 - 使用 Unity 5.2.x 到 5.3.4,以及 Android 4.4 - 6.1 - 总是给我一个 403 响应,而在 iOS.
上工作正常
所以,我有一个方法需要一个字节[]然后这样做:
WWW w = new WWW("https://my-amazon-function-to-call");
yield return w;
if (!string.IsNullOrEmpty(w.error)) {
Debug.LogError(w.error);
}
else
{
var dict = Json.Deserialize(w.text) as Dictionary<string,object>;
string oneTimeUploadUrl = (string)dict["oneTimeUploadUrl"]; // Private URL
string resultUrl = (string)dict["resultUrl"]; // Public URL
UnityWebRequest aws = UnityWebRequest.Put(oneTimeUploadUrl, bytes);
yield return aws.Send();
if(aws.isError)
{
Debug.LogError("AWS ERROR: " + aws.error);
}
if(aws.responseCode == 200)
{
FeedShare(new Uri(resultUrl), _cachedMessage); // FB call
}
}
很简单,对吧?
在 iOS 上,是的。但是 Android 它不断给我 PUT 操作的 403 响应。
所以,我已经开始将它包装在一个 iOS-specific #ifdef 中并尝试一些更原生的 C-Sharp-ish 用于 Android... 例如:
WWW w = new WWW("https://my-amazon-function-to-call"); // tried pure old Http too
yield return w;
if (!string.IsNullOrEmpty(w.error)) {
Debug.LogError(w.error);
}
else {
var dict = Json.Deserialize(w.text) as Dictionary<string,object>;
string oneTimeUploadUrl = (string)dict["oneTimeUploadUrl"];
string resultUrl = (string)dict["resultUrl"];
#if UNITY_IPHONE
UnityWebRequest aws = UnityWebRequest.Put(oneTimeUploadUrl, bytes);
yield return aws.Send();
if(aws.isError)
{
Debug.LogError("AWS ERROR: " + aws.error);
}
if(aws.responseCode == 200)
{
FeedShare(new Uri(resultUrl), _cachedMessage);
}
#else
// Various Security Callback Tests
//ServicePointManager.ServerCertificateValidationCallback = (p1, p2, p3, p4) => true;
//ServicePointManager.ServerCertificateValidationCallback = MyRemoteCertificateValidationCallback;
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(AcceptAllCertifications);
HttpWebRequest wreq = (HttpWebRequest)WebRequest.Create(oneTimeUploadUrl);
//wreq.AuthenticationLevel = System.Net.Security.AuthenticationLevel.None;
//wreq.PreAuthenticate = false;
wreq.Method = "PUT";
wreq.ContentType = "image/png";
wreq.ContentLength = bytes.Length;
Stream newStream = wreq.GetRequestStream();
newStream.Write(bytes, 0, bytes.Length);
newStream.Close();
HttpWebResponse response = (HttpWebResponse)wreq.GetResponse();
if((int)response.StatusCode == 200)
{
FeedShare(new Uri(resultUrl), _cachedMessage);
}
#endif
}
... 但这也给了我一个 403。我尝试了几个不同的选项,正如您从注释掉的代码中看到的那样,但没有爱。作为记录,以下是用作 ServerCertificateValidationCallbacks 的 SSL 策略函数:
public bool AcceptAllCertifications(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certification, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
return true;
}
public bool MyRemoteCertificateValidationCallback(System.Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
bool isOk = true;
if (sslPolicyErrors != SslPolicyErrors.None) {
for (int i=0; i<chain.ChainStatus.Length; i++) {
if (chain.ChainStatus [i].Status != X509ChainStatusFlags.RevocationStatusUnknown) {
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan (0, 1, 0);
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
bool chainIsValid = chain.Build ((X509Certificate2)certificate);
if (!chainIsValid) {
isOk = false;
}
}
}
}
print("MyRemoteCertificateValidationCallback: " + isOk);
return isOk;
}
这是实际的 StackTrace:
04-01 11:14:57.325: I/Unity(22979):
04-01 11:14:57.325: I/Unity(22979): (Filename: ./artifacts/generated/common/runtime/UnityEngineDebugBindings.gen.cpp Line: 37)
04-01 11:14:57.825: I/Unity(22979): WebException: The remote server returned an error: (403) Forbidden.
04-01 11:14:57.825: I/Unity(22979): at System.Net.HttpWebRequest.CheckFinalStatus (System.Net.WebAsyncResult result) [0x00000] in <filename unknown>:0
04-01 11:14:57.825: I/Unity(22979): at System.Net.HttpWebRequest.SetResponseData (System.Net.WebConnectionData data) [0x00000] in <filename unknown>:0
04-01 11:14:57.825: I/Unity(22979):
04-01 11:14:57.825: I/Unity(22979): (Filename: Line: -1)
在这一点上,我完全陷入困境...我唯一的想法是也许写一个本机插件...但我很乐意 NOT 必须这样做。 ..
想法 ???
我遇到了类似的问题,我总是得到 403。然后我发现我的服务器正在检查 Content-Type 和 User-Agent 在 HEADER 中。在我把它们放好之后,它就起作用了。我的代码是:
UnityWebRequest www = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST);
byte[] body = new System.Text.UTF8Encoding().GetBytes(json_string);
www.uploadHandler = (UploadHandler)new UploadHandlerRaw(body);
www.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
www.SetRequestHeader("Content-Type", "application/json");
www.SetRequestHeader("User-Agent", "DefaultBrowser");
www.SetRequestHeader("Cookie", string.Format("DummyCookie"));
www.chunkedTransfer = false;
yield return www.Send();
(( 我也在 Unity Answers 和 GameDev 上 post 编辑了这个但是 x-post 在这里以防任何 C# 网络负责人指出任何明显的错误我的 HttpWebRequest 代码...))
我正在尝试 post 通过他们的 SDK 将通过我的游戏捕获的图像发送到 Facebook,并且由于它需要 URI,我编写了一个简单的 AWS Lambda 函数来获取字节数组并将其上传到AWS 存储桶。 AWS 函数接受一个调用,然后 returns a URL 调用 PUT 来处理图像数据... 所以想法是,如果响应是 200,请使用 URL 到 post 到 FB。
但是 - 使用 Unity 5.2.x 到 5.3.4,以及 Android 4.4 - 6.1 - 总是给我一个 403 响应,而在 iOS.
上工作正常所以,我有一个方法需要一个字节[]然后这样做:
WWW w = new WWW("https://my-amazon-function-to-call");
yield return w;
if (!string.IsNullOrEmpty(w.error)) {
Debug.LogError(w.error);
}
else
{
var dict = Json.Deserialize(w.text) as Dictionary<string,object>;
string oneTimeUploadUrl = (string)dict["oneTimeUploadUrl"]; // Private URL
string resultUrl = (string)dict["resultUrl"]; // Public URL
UnityWebRequest aws = UnityWebRequest.Put(oneTimeUploadUrl, bytes);
yield return aws.Send();
if(aws.isError)
{
Debug.LogError("AWS ERROR: " + aws.error);
}
if(aws.responseCode == 200)
{
FeedShare(new Uri(resultUrl), _cachedMessage); // FB call
}
}
很简单,对吧? 在 iOS 上,是的。但是 Android 它不断给我 PUT 操作的 403 响应。
所以,我已经开始将它包装在一个 iOS-specific #ifdef 中并尝试一些更原生的 C-Sharp-ish 用于 Android... 例如:
WWW w = new WWW("https://my-amazon-function-to-call"); // tried pure old Http too
yield return w;
if (!string.IsNullOrEmpty(w.error)) {
Debug.LogError(w.error);
}
else {
var dict = Json.Deserialize(w.text) as Dictionary<string,object>;
string oneTimeUploadUrl = (string)dict["oneTimeUploadUrl"];
string resultUrl = (string)dict["resultUrl"];
#if UNITY_IPHONE
UnityWebRequest aws = UnityWebRequest.Put(oneTimeUploadUrl, bytes);
yield return aws.Send();
if(aws.isError)
{
Debug.LogError("AWS ERROR: " + aws.error);
}
if(aws.responseCode == 200)
{
FeedShare(new Uri(resultUrl), _cachedMessage);
}
#else
// Various Security Callback Tests
//ServicePointManager.ServerCertificateValidationCallback = (p1, p2, p3, p4) => true;
//ServicePointManager.ServerCertificateValidationCallback = MyRemoteCertificateValidationCallback;
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(AcceptAllCertifications);
HttpWebRequest wreq = (HttpWebRequest)WebRequest.Create(oneTimeUploadUrl);
//wreq.AuthenticationLevel = System.Net.Security.AuthenticationLevel.None;
//wreq.PreAuthenticate = false;
wreq.Method = "PUT";
wreq.ContentType = "image/png";
wreq.ContentLength = bytes.Length;
Stream newStream = wreq.GetRequestStream();
newStream.Write(bytes, 0, bytes.Length);
newStream.Close();
HttpWebResponse response = (HttpWebResponse)wreq.GetResponse();
if((int)response.StatusCode == 200)
{
FeedShare(new Uri(resultUrl), _cachedMessage);
}
#endif
}
... 但这也给了我一个 403。我尝试了几个不同的选项,正如您从注释掉的代码中看到的那样,但没有爱。作为记录,以下是用作 ServerCertificateValidationCallbacks 的 SSL 策略函数:
public bool AcceptAllCertifications(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certification, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
return true;
}
public bool MyRemoteCertificateValidationCallback(System.Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) {
bool isOk = true;
if (sslPolicyErrors != SslPolicyErrors.None) {
for (int i=0; i<chain.ChainStatus.Length; i++) {
if (chain.ChainStatus [i].Status != X509ChainStatusFlags.RevocationStatusUnknown) {
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan (0, 1, 0);
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
bool chainIsValid = chain.Build ((X509Certificate2)certificate);
if (!chainIsValid) {
isOk = false;
}
}
}
}
print("MyRemoteCertificateValidationCallback: " + isOk);
return isOk;
}
这是实际的 StackTrace:
04-01 11:14:57.325: I/Unity(22979):
04-01 11:14:57.325: I/Unity(22979): (Filename: ./artifacts/generated/common/runtime/UnityEngineDebugBindings.gen.cpp Line: 37)
04-01 11:14:57.825: I/Unity(22979): WebException: The remote server returned an error: (403) Forbidden.
04-01 11:14:57.825: I/Unity(22979): at System.Net.HttpWebRequest.CheckFinalStatus (System.Net.WebAsyncResult result) [0x00000] in <filename unknown>:0
04-01 11:14:57.825: I/Unity(22979): at System.Net.HttpWebRequest.SetResponseData (System.Net.WebConnectionData data) [0x00000] in <filename unknown>:0
04-01 11:14:57.825: I/Unity(22979):
04-01 11:14:57.825: I/Unity(22979): (Filename: Line: -1)
在这一点上,我完全陷入困境...我唯一的想法是也许写一个本机插件...但我很乐意 NOT 必须这样做。 ..
想法 ???
我遇到了类似的问题,我总是得到 403。然后我发现我的服务器正在检查 Content-Type 和 User-Agent 在 HEADER 中。在我把它们放好之后,它就起作用了。我的代码是:
UnityWebRequest www = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST);
byte[] body = new System.Text.UTF8Encoding().GetBytes(json_string);
www.uploadHandler = (UploadHandler)new UploadHandlerRaw(body);
www.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
www.SetRequestHeader("Content-Type", "application/json");
www.SetRequestHeader("User-Agent", "DefaultBrowser");
www.SetRequestHeader("Cookie", string.Format("DummyCookie"));
www.chunkedTransfer = false;
yield return www.Send();