What could be the reason for a SocketTimeoutException on android but not on Postman?

huangapple go评论67阅读模式
英文:

What could be the reason for a SocketTimeoutException on android but not on Postman?

问题

我有一个使用gingorm帮助创建的Golang服务器和API。它之前一直工作正常,但最近出现了一些奇怪的问题。在我的安卓应用中使用Retrofit调用API之前,我会在Postman上进行测试。就在昨天,我尝试调用登录API以获取后续需要的JWT令牌。在Postman上,登录功能正常。但是昨天开始,由于出现了SocketTimeoutException,登录在安卓应用中无法正常工作了。我不知道是什么原因导致的。在Postman上显示调用只花了大约10秒钟,而且我已经使用以下代码将Retrofit的超时时间增加到了180秒:

private val httpClient = OkHttpClient.Builder()
        .connectTimeout(180, TimeUnit.SECONDS)
        .writeTimeout(180, TimeUnit.SECONDS)
        .readTimeout(180, TimeUnit.SECONDS)

但问题仍然存在。我不确定之前在服务器上添加的代码是否导致了这个问题,但现在它并没有被调用。这段代码用于启动一个套接字服务器,但由于某种原因(尽管它是来自googollee的官方示例代码),它似乎无法正常工作。以下是代码示例:

package helpers

import (
	"fmt"
	"net/http"

	socketio "github.com/googollee/go-socket.io"
	"github.com/googollee/go-socket.io/engineio"
	"github.com/googollee/go-socket.io/engineio/transport"
	"github.com/googollee/go-socket.io/engineio/transport/polling"
	"github.com/googollee/go-socket.io/engineio/transport/websocket"
)

const (
	SERVER_HOST = "localhost"
	SERVER_PORT = "60051"
	SERVER_TYPE = "tcp"
)

var allowOriginFunc = func(r *http.Request) bool {
	return true
}

func StartSocket() {

	server := socketio.NewServer(&engineio.Options{
		Transports: []transport.Transport{
			&polling.Transport{
				CheckOrigin: allowOriginFunc,
			},
			&websocket.Transport{
				CheckOrigin: allowOriginFunc,
			},
		},
	})

	server.OnConnect("/", func(s socketio.Conn) error {
		s.SetContext("")
		fmt.Println("connected:", s.ID())
		return nil
	})

	server.OnEvent("/", "notice", func(s socketio.Conn, msg string) {
		fmt.Println("notice:", msg)
		s.Emit("reply", "have "+msg)
	})

	server.OnError("/", func(s socketio.Conn, e error) {
		fmt.Println("meet error:", e)
	})

	server.OnDisconnect("/", func(s socketio.Conn, reason string) {
		fmt.Println("closed", reason)
	})

	go server.Serve()
	defer server.Close()

	http.Handle("/socket.io/", server)
	http.Handle("/", http.FileServer(http.Dir("./asset")))

	fmt.Println("ScktSrv Serving at localhost:8000...")
	fmt.Print(http.ListenAndServe(":8000", nil))
}

服务器和模拟器都在我的电脑上运行。

更新:
以下是安卓代码的示例,它有点复杂,但基本上只是一个Retrofit调用:

val username = binding.txtUsername.text.toString()
val password = binding.txtPassword.text.toString()

val account = Account("", "", "", username, password, mutableListOf())

scope.launch {
    val inAPIDataResp = retFetchHlpr.fetchAPIData{ atlAPI.loginAccount(account) }
    
    //一些处理接收到的响应的代码
}

Retrofit端点设置如下:

@Headers("Content-Type: application/json")
@POST("/account/login")
suspend fun loginAccount(
    @Body data: Account
) : Response<AccountLoginResponse>

这是我的辅助类中的代码:

suspend fun <V> fetchAPIData(apiGetterFunc: suspend () -> Response<V>): V? {
    val actsResult: Response<V>?
    if( utils.isInternetAvailable(ctx) ){
        try{
            actsResult = apiGetterFunc.invoke()

            val respBody = retrofitErrorHandler(actsResult)
            if (respBody != null){
                return respBody
            }
        }catch (e: Exception){
            Log.e(TAG, "Retrofit Error: ${e.localizedMessage}")
        }
    }
    return null
}

private fun <T> retrofitErrorHandler(res: Response<T>): T {
    if (res.isSuccessful) {
        Log.d(TAG, "retrofitErrorHandler success: ${res.body()}")
        return res.body()!!
    } else {
        Log.d(TAG, "retrofitErrorHandler errMsg: ${res.errorBody().toString()}")
        throw Exception(res.errorBody().toString())
    }
}

我得到的错误是:

Retrofit Error: failed to connect to /192.168.45.102 (port 5000) from
/10.0.2.16 (port 54552) after 180000ms: isConnected failed: ETIMEDOUT
(Connection timed out)

我尝试将我的电脑和运行该应用的平板连接到我的手机热点,但仍然出现这个错误。

英文:

I have a Golang server with an API created with the help of gin and gorm. It was working fine until recently when it's having some weird behavior. Before calling the API on my android app using Retrofit, I'd test it on Postman. Just yesterday, I tried to call the login API to get the JWT token that is needed for the other API calls I'd need later on. On Postman, the login was working fine. But yesterday, the login doesn't work on the android app anymore because of the SocketTimeoutException. And I don't know what's causing that. On Postman, it said that it only took 10-ish seconds to finish the call, and I already increased the timeout of Retrofit to 180s using these lines of code:

private val httpClient = OkHttpClient.Builder()
.connectTimeout(180, TimeUnit.SECONDS)
.writeTimeout(180, TimeUnit.SECONDS)
.readTimeout(180, TimeUnit.SECONDS)

and the issue still persist. I'm not sure if a code I added on the server before is causing this, but it isn't being called right now. It's some code for starting a socket server, which doesn't seem to really work right now for some reason(even though it's an official sample code from googollee). Here it is:

package helpers
import (
&quot;fmt&quot;
&quot;net/http&quot;
socketio &quot;github.com/googollee/go-socket.io&quot;
&quot;github.com/googollee/go-socket.io/engineio&quot;
&quot;github.com/googollee/go-socket.io/engineio/transport&quot;
&quot;github.com/googollee/go-socket.io/engineio/transport/polling&quot;
&quot;github.com/googollee/go-socket.io/engineio/transport/websocket&quot;
)
const (
SERVER_HOST = &quot;localhost&quot;
SERVER_PORT = &quot;60051&quot;
SERVER_TYPE = &quot;tcp&quot;
)
var allowOriginFunc = func(r *http.Request) bool {
return true
}
func StartSocket() {
server := socketio.NewServer(&amp;engineio.Options{
Transports: []transport.Transport{
&amp;polling.Transport{
CheckOrigin: allowOriginFunc,
},
&amp;websocket.Transport{
CheckOrigin: allowOriginFunc,
},
},
})
server.OnConnect(&quot;/&quot;, func(s socketio.Conn) error {
s.SetContext(&quot;&quot;)
fmt.Println(&quot;connected:&quot;, s.ID())
return nil
})
server.OnEvent(&quot;/&quot;, &quot;notice&quot;, func(s socketio.Conn, msg string) {
fmt.Println(&quot;notice:&quot;, msg)
s.Emit(&quot;reply&quot;, &quot;have &quot;+msg)
})
server.OnError(&quot;/&quot;, func(s socketio.Conn, e error) {
fmt.Println(&quot;meet error:&quot;, e)
})
server.OnDisconnect(&quot;/&quot;, func(s socketio.Conn, reason string) {
fmt.Println(&quot;closed&quot;, reason)
})
go server.Serve()
defer server.Close()
http.Handle(&quot;/socket.io/&quot;, server)
http.Handle(&quot;/&quot;, http.FileServer(http.Dir(&quot;./asset&quot;)))
fmt.Println(&quot;ScktSrv Serving at localhost:8000...&quot;)
fmt.Print(http.ListenAndServe(&quot;:8000&quot;, nil))
}

Both the server and the emulator are running on my PC

UPDATE:
Here's what the android code looks like, it's kinda complex but it's basically just a Retrofit call:

val username = binding.txtUsername.text.toString()
val password = binding.txtPassword.text.toString()
val account = Account(&quot; &quot;, &quot; &quot;, &quot; &quot;, username, password, mutableListOf())
scope.launch {
val inAPIDataResp = retFetchHlpr.fetchAPIData{ atlAPI.loginAccount(account) }
//some code for processing the received response
}

//Retrofit endpoint setup

@Headers(&quot;Content-Type: application/json&quot;)
@POST(&quot;/account/login&quot;)
suspend fun loginAccount(
@Body data: Account
) : Response&lt;AccountLoginResponse&gt;

Here's the code from my helper class:

suspend fun &lt;V&gt; fetchAPIData(apiGetterFunc: suspend () -&gt; Response&lt;V&gt;): V? {
val actsResult: Response&lt;V&gt;?
if( utils.isInternetAvailable(ctx) ){
try{
actsResult = apiGetterFunc.invoke()
val respBody = retrofitErrorHandler(actsResult)
if (respBody != null){
return respBody
}
}catch (e: Exception){
Log.e(TAG, &quot;Retrofit Error: ${e.localizedMessage}&quot;)
}
}
return null
}
private fun &lt;T&gt; retrofitErrorHandler(res: Response&lt;T&gt;): T {
if (res.isSuccessful) {
Log.d(TAG, &quot;retrofitErrorHandler success: ${res.body()}&quot;)
return res.body()!!
} else {
Log.d(TAG, &quot;retrofitErrorHandler errMsg: ${res.errorBody().toString()}&quot;)
throw Exception(res.errorBody().toString())
}
}

The error I'm getting is:

> Retrofit Error: failed to connect to /192.168.45.102 (port 5000) from
> /10.0.2.16 (port 54552) after 180000ms: isConnected failed: ETIMEDOUT
> (Connection timed out)

I tried connecting my PC and a tablet running the app to my phone's hotspot and I still get this error.

答案1

得分: 1

我认为我已经找到了一个解决方案。为OkHttpClient添加.protocols(listOf(Protocol.HTTP_1_1))似乎可以使Retrofit正常工作。在这里找到了答案。

英文:

I think I already found a solution. Adding .protocols(listOf(Protocol.HTTP_1_1)) for the OkHttpClient seems to make Retrofit work fine again. Found the answer here

huangapple
  • 本文由 发表于 2023年6月22日 08:50:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76528007.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定