[JAVA] Lancer une requête PATCH avec HttpURLConnection

Lorsque je voulais effectuer une communication API lors de la création d'une application Android, je devais l'implémenter sans utiliser la bibliothèque OSS pour une raison quelconque. Par conséquent, j'ai créé ma propre partie de communication en utilisant HttpURLConnection.

Cependant, une erreur se produit lorsque je souhaite envoyer une requête PATCH. Il semble que HttpURLConnection ne puisse pas faire de requêtes PATCH. Mentir ... à droite ...

Il existe également un moyen d'usurper en utilisant l'en-tête X-HTTP-Method-Override, mais cela semble incertain en raison des dépendances côté serveur. https://stackoverflow.com/questions/25163131/httpurlconnection-invalid-http-method-patch

Comment faites-vous la bibliothèque OSS? Reportez-vous donc au Code public de la bibliothèque client HTTP appelée Jersey. Et l'a mis en œuvre. C'est une petite bibliothèque ancienne, mais j'ai pu confirmer son fonctionnement.

Exemple d'implémentation

Implémentez la classe HttpClient comme suit. Cette fois, l'authentification du support est supposée.

HttpClient.kt



internal class HttpClient {
    companion object {

        fun patch(url: String, accessToken: String? = null, body: String? = null): Pair<Int, String?> {
            var responseJsonString: String? = null
            val urlTmp = URL(url)
            val con = urlTmp.openConnection() as HttpURLConnection
            try {
                setRequestMethodViaJreBugWorkaround( con, "PATCH")
                con.instanceFollowRedirects = false
                con.doOutput = true
                con.connectTimeout = 60000
                con.readTimeout = 60000
                con.setRequestProperty("Content-Type", "application/json")
                con.setRequestProperty("Accept", "application/json")
                if(accessToken != null) con.setRequestProperty("Authorization", "Bearer $accessToken")
                if(body != null) {
                    val os: OutputStream = con.outputStream
                    val ps = PrintStream(os)
                    ps.print(body)
                    ps.close()
                }
                val reader: BufferedReader
                reader = if (con.responseCode == HttpURLConnection.HTTP_OK) {
                    BufferedReader(InputStreamReader(con.inputStream, "UTF-8"))
                } else {
                    BufferedReader(InputStreamReader(con.errorStream, "UTF-8"))
                }
                responseJsonString = reader.readLine()
                con.disconnect()
            } catch (e: Exception) {
                e.printStackTrace()
                Log.e("ApiClientException", e.toString())
            }
            return con.responseCode to responseJsonString
        }

        private fun setRequestMethodViaJreBugWorkaround(httpURLConnection: HttpURLConnection, method: String) {
            try {
                httpURLConnection.requestMethod = method // Check whether we are running on a buggy JRE
            } catch (pe: ProtocolException) {
                try {
                    AccessController.doPrivileged(PrivilegedExceptionAction<Any?> {
                        try {
                            httpURLConnection.requestMethod = method
                            // Check whether we are running on a buggy
                            // JRE
                        } catch (pe: ProtocolException) {
                            var connectionClass: Class<*>? = httpURLConnection.javaClass
                            val delegateField: Field?
                            try {
                                delegateField = connectionClass!!.getDeclaredField("delegate")
                                delegateField.isAccessible = true
                                val delegateConnection = delegateField[httpURLConnection] as HttpURLConnection
                                setRequestMethodViaJreBugWorkaround(delegateConnection, method)
                            } catch (e: NoSuchFieldException) {
                                // Ignore for now, keep going
                            } catch (e: IllegalArgumentException) {
                                throw RuntimeException(e)
                            } catch (e: IllegalAccessException) {
                                throw RuntimeException(e)
                            }
                            try {
                                var methodField: Field
                                while (connectionClass != null) {
                                    try {
                                        methodField = connectionClass.getDeclaredField("method")
                                    } catch (e: NoSuchFieldException) {
                                        connectionClass = connectionClass.superclass
                                        continue
                                    }
                                    methodField.isAccessible = true
                                    methodField[httpURLConnection] = method
                                    break
                                }
                            } catch (e: java.lang.Exception) {
                                throw RuntimeException(e)
                            }
                        }
                        null
                    })
                } catch (e: PrivilegedActionException) {
                    val cause: Throwable? = e.cause
                    if (cause is RuntimeException) {
                        throw cause
                    } else {
                        throw RuntimeException(cause)
                    }
                }
            }
        }
    }
}

Exemple d'utilisation

Importez le HttpClient ci-dessus et utilisez-le comme suit.

fun patchRequestSample() {
    val (statusCode, responseJsonString) = HttpClient.patch("https://hoge/users/10", accessToken ="xxxx", body = sampleJson.toString())
}

Le code d'état est retourné dans statusCode et la réponse est retournée dans responseJsonString.

Même si je l'ai recherché, je n'ai trouvé que comment remplacer l'en-tête, je vais donc le laisser comme rappel.

Recommended Posts

Lancer une requête PATCH avec HttpURLConnection
Comment demander un fichier CSV au format JSON avec jMeter
[Java] Lancer une requête et afficher l'écran (GET / POST)
Créez un terrain de jeu avec Xcode 12
Une histoire bloquée avec NotSerializableException
Choses à oublier lors de l'interception d'une requête avec Android WebView # shouldInterceptRequest