java.io.NotSerializableException:Jenkins管道中的sun.net.www.protocol.https.HttpsURLConnectionImpl

时间:2018-11-08 10:31:39

标签: jenkins jenkins-pipeline

关于它的含义和处理方法的讨论很多,但是使用@NonCPS的主要解决方案似乎不起作用。这是相关的代码段:

@NonCPS
def restCall(String method, String resource, String data = '') {
    def URL url = new URL("${Params.REST_BASE_URI}/${resource}")
    def HttpURLConnection connection = url.openConnection()

    withCredentials([usernamePassword(credentialsId: 'restful-api', passwordVariable: 'RA_PASS', usernameVariable: 'RA_USER')]) {
        String encoded = Base64.getEncoder().encodeToString(("${env.RA_USER}:${env.RA_PASS}").getBytes(StandardCharsets.UTF_8))
        connection.setRequestProperty("Authorization", "Basic ${encoded}");
    }

    connection.setRequestProperty("content-type", "application/json");
    connection.setRequestMethod(method)
    connection.doOutput = true

    if (data != '') {
        def writer = new OutputStreamWriter(connection.outputStream)
        writer.write(data)
        writer.flush()
        writer.close()
    }

    connection.connect();

    def statusCode =  connection.responseCode
    if (statusCode != 200 && statusCode != 201) {
        throw new Exception(connection.getErrorSteam().text)
    }

    return connection.content.text
}

请注意,该函数上确实有@NonCPS。但是执行此操作仍会产生相同的错误:

an exception which occurred:
    in field groovy.lang.Reference.value
    in object groovy.lang.Reference@1375b00
    in field WorkflowScript$_bitbucketCall_closure1.connection
    in object WorkflowScript$_bitbucketCall_closure1@b3001c
    in field org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.closures
    in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@144b2a6
    in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup@144b2a6
Caused: java.io.NotSerializableException: sun.net.www.protocol.https.HttpsURLConnectionImpl
    at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:860)
    at ...

我该如何解决?

1 个答案:

答案 0 :(得分:3)

结果是,不需要@NonCPS注释即可实现我的目标。相反,我需要做的就是确保在方法调用结束时,仍然没有初始化任何不可序列化的变量。因此,以下方法可以正常工作:

def restCall(String method, String resource, String data = '') {
    def URL url = new URL("${Params.REST_BASE_URI}/${resource}")
    def HttpURLConnection connection = url.openConnection()

    withCredentials([usernamePassword(credentialsId: 'restful-api', passwordVariable: 'RA_PASS', usernameVariable: 'RA_USER')]) {
        String encoded = Base64.getEncoder().encodeToString(("${env.RA_USER}:${env.RA_PASS}").getBytes(StandardCharsets.UTF_8))
        connection.setRequestProperty("Authorization", "Basic ${encoded}");
    }

    connection.setRequestProperty("content-type", "application/json");
    connection.setRequestMethod(method)
    connection.doOutput = true

    if (data != '') {
        def writer = new OutputStreamWriter(connection.outputStream)
        writer.write(data)
        writer.flush()
        writer.close()
    }

    connection.connect();

    def statusCode =  connection.responseCode
    if (statusCode != 200 && statusCode != 201) {
        String text = connection.getErrorStream().text
        connection = null
        throw new Exception(text)
    }

    String text = connection.content.text
    connection = null
}

诀窍是在执行该方法之前显式设置connection = null