Xử lí lỗi 415 Spring boot

Chào mọi người. Mình có chút vẫn đề mong mọi người giải đáp.

Mình đang thực hiện làm ứng dụng web có sử dụng thanh toán của momo. Khi thanh toán xong, bên Momo sẽ trả về kết quả của giao dịch như hình bên dưới nhưng hiện tại mình chưa có cách nào để lấy được response của server Momo về do xảy ra lỗi “415 unsupported media type”.

Mình đã thử tạo ra 1 object để có các trường giống như response Momo trả về nhưng vẫn chưa được.

Mọi người có idea gì cho vấn đề này không ạ.
image

Trích từ MDN web docs(mấy thứ liên quan đến web thì cứ lên đây xem), link:

"The HTTP 415 Unsupported Media Type client error response code indicates that the server refuses to accept the request because the payload format is in an unsupported format.

The format problem might be due to the request’s indicated Content-Type or Content-Encoding , or as a result of inspecting the data directly."

Tạm dịch: "Mã lỗi 415 Unsupported Media Type(415 Không hỗ trợ kiểu dữ liệu?) cho biết rằng máy chủ đã từ chối chấp nhận request vì định dạng payload(json, form-urlencoded, multipart/formdata,…) là định dạng không được hỗ trợ.

Vấn đề định dạng có thể xảy ra do Content-Type hoặc Content-Encoding(ở trong header của request) được chỉ định bởi request(gửi lên server) có vấn đề, hoặc là kết quả của việc kiểm tra dữ liệu trực tiếp(?)."

Nếu bạn thấy mình dịch hơi củ chuối và khó hiểu quá thì mong thông cảm, mình không giỏi tiếng Anh lắm :smiley:. Cứ hiểu đơn giản là ở trong request mà bạn gửi lên, trong phần header, phần Content-Type hoặc Content-Encoding ghi cái gì đó khiến server không hiểu nên từ chối, thường là do Content-Type. Bạn thử kiểm tra xem trong cái request mà bạn gửi lên, trong phần Content-Type hoặc Content-Encoding có đúng cái mà bên Momo yêu cầu không.

3 Likes

Request này không phải do mình gửi lên mà là do server của Momo trả về kết quả của giao dịch vừa được thực hiện.

@huuthanh1
Cậu có thể share bọn tớ document mà cậu refer tới từ Momo API được không? Document mà cậu chụp ảnh này:

Trong document của Momo, chắc chắn sẽ có đề cập tới Content-Type ở mục request header. Bên Momo tớ nghĩ họ validate phần đó.
Đây là 1 ví dụ:

Cậu nên đọc kỹ document của họ, và đọc lại comment @HR16 đề cập ở trên để hiểu 415 nghĩa là gì.

2 Likes

Mô hình giữa server và client là: Client gửi request(yêu cầu) lên server, server trả response(phản hồi) cho cái request đó về client mà bạn.

3 Likes

Ý mình là khi mình bắt cái response của Momo trả về sever của mình thì nó xảy ra lỗi 415 (không support kiểu dữ liệu trả về). Mình đang không hiểu tại sao lại xảy ra vậy, conten type của họ là “application/x-www-form-urlencoded”

Đây là doc mà bên Momo cung cấp cho người dùng và minhf đã sử dụng để làm: https://developers.momo.vn/#/docs/aio/atm?id=ipn-instant-payment-notification

Hmmm… Vậy là ở đây server của Momo là client, nãy giờ cứ tưởng client là server của bạn :rofl:. Vậy là lỗi này là do server của bạn chưa có config để nhận Content-Type là “application/x-www-form-urlencoded”, mình đoán vậy.

2 Likes

Mình không biết gì về Spring boot nhưng mình thấy cái này có vẻ liên quan, không biết có đúng cái mà bạn cần không :smiley:

1 Like

Cảm ơn Thanh nhé!

Tớ hiểu rồi.
Trước hết, tớ nghĩ sẽ tốt hơn cho việc loại trừ các nguyên nhân nếu cậu cung cấp cho bọn tớ 1 vài thông tin sau:

  • Cậu gửi cho bọn tớ request body cậu gửi tới POST /gw_payment/transactionProcessor được không? Phần này chỉ để confirm lại notifyUrl thôi, nên cậu đừng đưa production data cho bọn tớ, chỉ cần domain/{api của cậu} là được.
  • Cậu có thể cho bọn tớ đoạn code cậu config notify URL không? Nếu tớ không nhầm, đó là /order/payment/response API.
    Tớ kỳ vọng cậu đưa cho bọn tớ đoạn code kiểu như thế này (không cần đưa bọn tớ implementation của method đâu):
@RequestMapping(value = "/{email}/authenticate", method = RequestMethod.POST,
        consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, 
        produces = {MediaType.APPLICATION_ATOM_XML_VALUE, MediaType.APPLICATION_JSON_VALUE})
public @ResponseBody  Representation authenticate(@PathVariable("email") String anEmailAddress, MultiValueMap paramMap) throws Exception {
    //...
}

Cậu có thể đổi tên method đó nếu như cậu cần bảo mật thông tin.

Như @HR16 có đề cập, tớ nghĩ cậu chắc chỉ gặp vấn đề với việc config API để support “application/x-www-form-urlencoded” content-type.

1 Like

Đây là cấu trúc code của t.
Đầu tiên t tạo một hàm để lấy ra link thanh toán PayUrl.
Hàm này trả về một link thanh toán dùng để thanh toán momo.

public String DisplayPaymentScreen(String order_id)
{
    String payUrl = new String();
    try {
        Order order = orderService.findOneById(order_id).getData();

        PartnerInfo devInfo = new PartnerInfo("", "", ""); // partnerCode: "", accessKey: "", secretKey: ""
        String requestId = order.getId();
        String orderId = order.getId();
        long amount = 50000;

        String orderInfo = "Pay With Momo";
        String returnURL = "http://localhost:8803/order/payment/response/" + order.getId() + "/" + requestId;
        String notifyURL = "https://c8e6dac89328.ngrok.io/order/response";
        String extraData = "";
        String bankCode = "SML";

        Environment environment = new Environment("https://test-payment.momo.vn/gw_payment/transactionProcessor", devInfo, Environment);

        CaptureMomoResponse captureMomoResponse = CaptureMomo.process(environment, orderId, requestId, Long.toString(amount), orderInfo, returnURL);
        payUrl = captureMomoResponse.getPayUrl();

    } catch (Exception e) {
        e.printStackTrace();
    }
    return payUrl;
}

Sau đó khi thanh toán xong, momo sẽ trả về kết quả thanh toán qua IPN. T tạo một PostMapping để đón dữ liệu từ momo. Nhưng đến đây thì xảy ra lỗi 415.

@PostMapping(value = "/payment/response", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public void IPNPayment(@Request InpMomo response)
{
    payment.IPNProcess(response);
}

T đã tạo một model để convert respone của momo theo định dạng dữ liệu trả về nhưng vẫn không được.

public class InpMomo {
    private String partnerCode;
    private  String accessKey;
    private String requestId;
    private String orderId;
    private long amount;
    private String orderInfo;
    private String orderType;
    private String transId;
    private int errorCode;
    private String message;
    private String localMessage;
    private String payType;
    private String responseTime;
    private String extraData;
    private String signature;
}
1 Like

Theo như @HR16 đã chỉ ra ở đây, cậu nên bỏ @RequestBodyIPNPayment đi.

@PostMapping(path = "/payment/response", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public void IPNPayment(IpnMomo response) {
  // ...
}

Với content-type là application/x-www-form-urlencoded , @RequestBody chỉ có tác dụng với MultiValueMap<?, ?> thôi cậu.

Reference: https://github.com/spring-projects/spring-framework/issues/22734

4 Likes

Cảm ơn câu và @HR16 đã support nhé. Mình sửa được rồi. Trước giờ mình vẫn nghĩ là @RequestBody là để lấy dữ liệu từ body của request trả về :smiley: :smiley: :smiley:

2 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?