Moya: Status code 405 returned for the first POST call of the app even when POST is an allowed method on the API.

Created on 7 Jan 2018  Âˇ  34Comments  Âˇ  Source: Moya/Moya

Moya version ->10.0.1

I am made a LoginAPI class with following method implementation.

public var method: Moya.Method {
        return .post
    }

The Login Service allows only POST HTTP method.
The issue is even after specifying Moya method as POST, the service response returns 405 status code in service call first time. If I retry the same call, status code 200 is returned.

Logs with 405 status code:
Request: https://myURL/login
Moya_Logger: [07/01/2018 21:08:54] Request Headers: ["Content-Type": "application/json"]
Moya_Logger: [07/01/2018 21:08:54] HTTP Request Method: POST
Moya_Logger: [07/01/2018 21:08:54] Request Body: {"password”:”password”,”email”:”[email protected]"}
Moya_Logger: [07/01/2018 21:08:54] Response: { URL: Request: https://myURL/login } { Status Code: 405, Headers {
Allow = (
POST
);
Date = (
"Sun, 07 Jan 2018 15:35:42 GMT"
);
"Transfer-Encoding" = (
Identity
);
} }

Logs with 200 Status code:
Request: https://myURL/login
Moya_Logger: [07/01/2018 21:12:35] Request Headers: ["Content-Type": "application/json"]
Moya_Logger: [07/01/2018 21:12:35] HTTP Request Method: POST
Moya_Logger: [07/01/2018 21:12:35] Request Body: {"password”:”password”,”email”:”[email protected]"}
Moya_Logger: [07/01/2018 21:12:38] Response: { URL: Request: https://myURL/login } { Status Code: 200, Headers {
"Content-Type" = (
"application/json;charset=UTF-8"
);
Date = (
"Sun, 07 Jan 2018 15:39:26 GMT"
);
"Transfer-Encoding" = (
Identity
);
} }

Points to note:

  1. This url works perfectly in Postman everytime with 200 status code with POST method.
  2. On simulator, this is the behavior first time I run the app (fresh launch of the app). On next run or on retrying , it works.
  3. Tested the api call by refactoring it to an Alamofire call, it works.

Could someone please help with what could be the possible cause for this?

bug? question stale

All 34 comments

Can you capture the packet when you request Post first time? Provide it can found the issue more specifically if you provide HTTP content.

@shwetachitlangia Please fill in the appropriate title, help others quickly understand your problem. :]

@zhongwuzw Sorry, I am unable to track packets using Wireshark. But i rewrote the same api call with Alamofire and tested with same conditions, it works.

The issue seems to be with the First POST operation of the app.
The first GET operations works just fine.

@shwetachitlangia without more information it's going to be hard to help you debug your issue. This would be a massive bug in Moya if it is an issue with Moya, but (from the fact that hundreds, if not thousands of apps are in production with Moya) it's more likely an issue with your code than the library.

Do you think you can make a Playground/example project that shows the issue? Without wireshark logs that would be most helpful for us to get your bug sorted out.

Can this code help?
Doesn't seem like a code issue as we are calling the same API again and it works.
Cannot share an example project as we have secured services.

//-------------------------------------------------------------------------
// Login APIs - Login user
//-------------------------------------------------------------------------

import Moya

let loginProvider = NetworkUtility.getMoyaProvider(LoginAPI.self)

public enum LoginAPI {
    case loginUser([String: Any])
    case forgotPasswordOTP(String)
    case resetPassword([String: Any])
}

extension LoginAPI: TargetType {

    public var baseURL: URL { return URL(string: ConfigData.shared.getURL(forKey: DefaultsKeys.baseURL))! }

    public var path: String {
        switch self {
        case .loginUser:
            return ConfigData.shared.getURL(forKey: DefaultsKeys.login)
        case .resetPassword:
            return ConfigData.shared.getURL(forKey: DefaultsKeys.resetPassword)
        case .forgotPasswordOTP:
            return ConfigData.shared.getURL(forKey: DefaultsKeys.forgotPasswordOTP)
        }
    }

    public var method: Moya.Method {
        switch self {
        case .loginUser:
            return .post
        case .resetPassword, .forgotPasswordOTP:
            return .put
        }
    }

    public var task: Task {
        switch self {

        case .loginUser(let bodyParameters),
              //UserLogin dictionaryRepresentation is used for this
             .resetPassword(let bodyParameters):
            return .requestCompositeParameters(bodyParameters: bodyParameters,
                                               bodyEncoding: JSONEncoding.default,
                                               urlParameters: [:])
        case .forgotPasswordOTP(let email):
            return .requestCompositeParameters(bodyParameters: [User.Keys.email: email],
                                               bodyEncoding: JSONEncoding.default,
                                               urlParameters: [:])
        }
    }

    public var headers: [String: String]? {
        return NetworkUtility.getHeaders()
    }

    public var sampleData: Data {
        var data: Data! = nil
        switch self {
        case .loginUser:
            data = NetworkUtility.loadJSON(jsonName: "3.33.4Success")
        case .resetPassword:
            data = NetworkUtility.loadJSON(jsonName: "ResetPassword")
        case .forgotPasswordOTP:
            data = NetworkUtility.loadJSON(jsonName: "VerifyUser")
        }
        return data
    }
}

@shwetachitlangia The above code snippet provides insufficient information. Or you can request third-party public services (for example: https://httpbin.org), see the test will appear the same problem? In order to troubleshoot the problem.

@yangcaimu Facing exactly the same issue. Sending the following POST request -

Request: http://XXXXXX/YYYY/UUUIIUIIUIUIUIUIU
Moya_Logger: [15/01/2018 16:10:08] Request Headers: ["Content-Type": "application/json", "correlationId": "876578658769389283kjhgf"]
Moya_Logger: [15/01/2018 16:10:08] HTTP Request Method: POST
Moya_Logger: [15/01/2018 16:10:08] Request Body: {"password":"password","email":"[email protected]"}..

Checked with server team, as per their logs, they are getting method type as "ST" instead of POST.

AS per Server Logs -
"o.s.web.servlet.DispatcherServlet - DispatcherServlet with name ‘dispatcherServlet’ processing ST request for [/YYYY/UUUIIUIIUIUIUIUIU]"

@karbhasin , strange behavior, maybe the only solution is to get requests raw packet from client-side and server-side, then compare them to find the issue.

Hi,

I am updating a project from Moya 7.0.0 (swift 2.x) to Moya 10.0.0, facing the same issue. @shwetachitlangia did you find any workarounds?

This is really strange and unfortunately all of you guys can't share your project to help us investigate it, right?

In that case, will any of you guys (@aloco, @karbhasin, @shwetachitlangia) want to make a quick call with me and we could try debug it on the fly? Being able to reproduce it and access to the server logs would be awesome.

@sunshinejr I can have a call with you. I can reproduce it. But don't have access to server logs.
My skype id is chitstcs.

@shwetachitlangia Did this issue occur after a migration to 10.0.1? If so, what was the previous Moya version where this issue was not present?

Sent with GitHawk

@SD10 we have started facing this issue from 10.0.0

Hi, trying to investigate the issue but it seems very strange to me. First it doesn´t happen with every POST request every time and secondly I just ran into the same issue with a DELETE call.

  "status" : 405,
  "message" : "Request method 'LETE' not supported",
  "timestamp" : 1516355038187,
  "exception" : "org.springframework.web.HttpRequestMethodNotSupportedException",

The request setup looks correct since MoyaLogger prints the request correctly. I think this happens also only with long url´s @shwetachitlangia can you confirm this?

Can you guys check with a proxy (like mitmproxy) to see if the request seems to be okay there as well?

@shwetachitlangia did this issue not show up on an earlier version? 9.x, for example?

@AndrewSB Yes, did not face it with 9.x.
The issue doesnot happen with every POST request.
If we hit one GET followed by a POST request, the POST fails with 405.

@aloco So, the issue is "POST" becomes "ST" and "DELETE" becomes "LETE".
The first two chars are truncated making it an invalid HTTP method.
Can anyone know the possible reason for this?

@shwetachitlangia I think only two reasons, one is iOS network system bug? because the http method like get、post.. appended on packet by system automatically . Another reason is server-side, truncated first two bytes when handle http. So as I said as before, only method to figure out is to catch network packets.

qq20180120-132129 2x

Hi All,
I was getting same issue.I have updated Moya version to the 10.0.1(it was 8.0.3).
At the first time I got issue with the headers in the target type.
I added the headers
public var headers: [String : String]? { let assigned: [String: String] = ["Content-Type": "application/json"] return assigned }
After that I got the issue with public var task: Task
In 8.0.3 Task Extension has only .request upload
In 10.0.3 `case requestPlain

/// A requests body set with data.
case requestData(Data)

/// A request body set with `Encodable` type
case requestJSONEncodable(Encodable)

/// A requests body set with encoded parameters.
case requestParameters(parameters: [String: Any], encoding: ParameterEncoding)`

So compare to both in 8.0.3 version request is handling entire .get and .post
In 10.0.3 version

`case requestPlain

/// A requests body set with data.
case requestData(Data)

/// A request body set with `Encodable` type
case requestJSONEncodable(Encodable)

/// A requests body set with encoded parameters.
**case requestParameters(parameters: [String: Any], encoding: ParameterEncoding)**`

Now the final result is
My Task extension is
` public var task: Task {

parameters coming from the extension

    if parameters?.count != nil
    {
        return .requestParameters(parameters: parameters!, encoding: JSONEncoding.default)
    }else{
        return .requestPlain

    }
}`

` public var parameters: [String: Any]? {
switch self {

    case .getData(_ , let dicParams):
        return dicParams
    case .postLoginDetails(_, let dicParams):
        return dicParams

}`

Hope it will be helpful Thanks..

It looks like we have 4 people experiencing this issue and they mention it wasn’t present in Moya 8.0. We refactored the Task object in Moya 9.0.

Can anyone who is experiencing the issue put together an example project that replicates it?

Tagging @Dschee in case he can give any insight

Sent with GitHawk

I've read through the thread, but I can't remember anything that might cause this error related with the refactoring of Task. Also the code was refactored quite a bit after me implementing the initial feature.

What I'd suggest the people seeings this issue to do:

  1. Downgrade to Moya 10.0.0 and see if the issue is there, still.
  2. Downgrade to Moya 9.0.0, possibly reverse-migrate your code if needed, then try that.

This way we can isolate the time frame the issue was introduced more exactly.

I tried mitmproxy but facing other issues with using the proxy (getting some timeouts 🤷‍♂️), will dig into it more when I find time, but so far, I haven´t seen the issue when using the proxy but don´t take my attempt as too meaningful as I tested this not excessively and sometimes the issue doesn´t show up, even without the proxy.

@Dschee Thanks...
I have three type of services in the same project.
Query Params and Path Params as GET
POST data with body.

I have written code like this in the Task it is absolutely working fine with the 10.0.1 version of Moya.

Here is my code.

` public var task: Task {

    switch self {
    case .getInboxMessages(_):
        return .requestCompositeData(bodyData: Data(), urlParameters: parameters!)
    case .getMembersList(_, _):
        return .requestCompositeData(bodyData: Data(), urlParameters: parameters!)

    default:

        if parameters?.count != nil
        {
            return .requestParameters(parameters: parameters!, encoding: JSONEncoding.default)
        }else{
            return .requestPlain

        }

    }


}`

@SD10 May I know the above logic is perfect or anything wrong.Now I am getting my results perfectly, However I need to check my entire project...
-- :relieved:

These are the server logs -
WARN 1885 --- [o-8081-exec-453] o.s.web.servlet.PageNotFound : Request method 'ST' not supported

'ST' means...? it should be 'POST' right?
Can u pls share your code how you are sending data.
Which version are you using..?

How many people are using Spring here?

@SD10 Yes, the Services team is using Spring Boot.

This issue has been marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

I suspect this issue is unrelated to Moya and is in fact a problem with Spring. Going to ask Mr. Stalebot to keep this open

Sent with GitHawk

This issue has been marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

This issue has been auto-closed because there hasn't been any activity for at least 21 days. However, we really appreciate your contribution, so thank you for that! 🙏 Also, feel free to open a new issue if you still experience this problem 👍.

I also encountered the same problem. After deleting the unused case in enum, the problem is solved. I don't know why.

I had this problem on react-native app (ios)
My solution for fix:
when i config axios request i set field DATA as null, not emply object {} !!

Was this page helpful?
0 / 5 - 0 ratings