重要说明-最后在Edit#2中取得了突破,因此请务必阅读该内容。

我陷入了困境,试图使用JDBC连接到我们公司的PostgreSQL服务器。服务器正在使用pgBouncer。

这是我的项目依赖项:

  :dependencies [[org.clojure/clojure "1.6.0"]
                 [org.clojure/java.jdbc "0.3.6"]
                 [org.postgresql/postgresql "9.4-1200-jdbc41"]]


这是我的代码:

(ns pg-test.core
  (:require [clojure.java.jdbc :as jdbc]))

(def db
  {:subprotocol "postgresql"
   :subname "//the-server-name:the-port/db-name"
   :sslmode "require"
   :user "my-username"
   :password "super-secret-password"})

(jdbc/query db ["SELECT 5"])


运行此代码时,得到以下三个结果之一:


org.postgresql.util.PSQLException:连接尝试失败。
org.postgresql.util.PSQLException:错误:错误的数据包标头:“ 70”
很少(现在三百次,数百次尝试),它实际上可以工作!返回({:?column? 5})




到底是怎么回事?为什么有时会起作用,但几乎永远不会起作用?



我的设定


OS X Yosemite(但是我也无法使它在我的Ubuntu虚拟机上运行。)
在emacs中,先按lein repl :headless :port 2358,再按cider-connect
服务器是postgres 9.1.12


编辑#2

刚刚了解了:loglevel 2选项。这将其设置为“ DEBUG”级别的输出,并且我收集了一些更有趣的数据。这是输出:

21:45:34.921 (31) PostgreSQL 9.4 JDBC4.1 (build 1200)
21:45:34.927 (31) Trying to establish a protocol version 3 connection to the-server-name:the-port
21:45:35.020 (31)  FE=> SSLRequest
21:45:35.120 (31)  <=BE SSLOk
21:45:35.120 (31) converting regular socket connection to ssl
21:45:35.324 (31) Receive Buffer Size is 131072
21:45:35.324 (31) Send Buffer Size is 131136
21:45:35.324 (31)  FE=> StartupPacket(user=my-username, database=db-name, client_encoding=UTF8, DateStyle=ISO, TimeZone=America/Denver, extra_float_digits=2)
21:45:35.435 (31)  <=BE AuthenticationReqMD5(salt=f244b442)
21:45:35.436 (31)  FE=> Password(md5digest=md52e3d9f29d44d48ab19ef3469d54d50d1)
21:45:35.520 (31)  <=BE ErrorMessage(ERROR: bad packet header: '70')


然后给出以下堆栈跟踪:

org.postgresql.util.PSQLException: ERROR: bad packet header: '70'
    at org.postgresql.core.v3.ConnectionFactoryImpl.doAuthentication(ConnectionFactoryImpl.java:420)
    at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:195)
    at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:66)
    at org.postgresql.jdbc2.AbstractJdbc2Connection.<init>(AbstractJdbc2Connection.java:127)
    at org.postgresql.jdbc3.AbstractJdbc3Connection.<init>(AbstractJdbc3Connection.java:29)
    at org.postgresql.jdbc3g.AbstractJdbc3gConnection.<init>(AbstractJdbc3gConnection.java:21)
    at org.postgresql.jdbc4.AbstractJdbc4Connection.<init>(AbstractJdbc4Connection.java:41)
    at org.postgresql.jdbc4.Jdbc4Connection.<init>(Jdbc4Connection.java:24)
    at org.postgresql.Driver.makeConnection(Driver.java:414)
    at org.postgresql.Driver.connect(Driver.java:282)
    at java.sql.DriverManager.getConnection(DriverManager.java:571)
    at java.sql.DriverManager.getConnection(DriverManager.java:187)
    at clojure.java.jdbc$get_connection.invoke(jdbc.clj:255)
    at clojure.java.jdbc$db_query_with_resultset.invoke(jdbc.clj:798)
    at clojure.java.jdbc$query.doInvoke(jdbc.clj:832)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at pg_test.core$eval4536.invoke(core.clj:14)
    at clojure.lang.Compiler.eval(Compiler.java:6703)
    at clojure.lang.Compiler.load(Compiler.java:7130)
    at pg_test.core$eval4524.invoke(form-init6588155330850041472.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6703)
    at clojure.lang.Compiler.eval(Compiler.java:6666)
    at clojure.core$eval.invoke(core.clj:2927)
    at clojure.main$repl$read_eval_print__6625$fn__6628.invoke(main.clj:239)
    at clojure.main$repl$read_eval_print__6625.invoke(main.clj:239)
    at clojure.main$repl$fn__6634.invoke(main.clj:257)
    at clojure.main$repl.doInvoke(main.clj:257)
    at clojure.lang.RestFn.invoke(RestFn.java:1523)
    at clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__592.invoke(interruptible_eval.clj:67)
    at clojure.lang.AFn.applyToHelper(AFn.java:152)
    at clojure.lang.AFn.applyTo(AFn.java:144)
    at clojure.core$apply.invoke(core.clj:624)
    at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1862)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at clojure.tools.nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:51)
    at clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__634$fn__637.invoke(interruptible_eval.clj:183)
    at clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__627.invoke(interruptible_eval.clj:152)
    at clojure.lang.AFn.run(AFn.java:22)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:745)


但是,它给出了这个错误代码!

SQLException: SQLState(08P01)


根据this website的意思是“协议违规”。

我在Google上搜索了08P01协议违规情况,并在this bug report上找到了一个完全不相关的项目,该项目在GitHub上尝试将编码的Unicode字符写入字符串字段时标题为“'08P01 PROTOCOL VIOLATION'”。

因此,让我们看一下我们要发送的内容:


StartupPacket(user=my-username, database=db-name, client_encoding=UTF8, DateStyle=ISO, TimeZone=America/Denver, extra_float_digits=2)。请注意,我们的编码为UTF8。
然后,我们发送Password(md5digest=md52e3d9f29d44d48ab19ef3469d54d50d1),并立即获得“坏数据包头'70'”异常。


UTF8是否再次毁了我的生活?我以为很久以前就把这些糟糕的日子抛在了身后。

所以现在我想知道是否有一种方法可以更改客户端编码。或可能更改所使用的身份验证方法。

最佳答案

根据PgJDBC驱动程序,“ PgJDBC对于某些功能具有对其他库的可选依赖项。如果您希望使用这些功能,则这些库也必须位于类路径上;否则,您将在运行时获得PSQLException。尝试使用缺少库的功能。”

可能缺少一些可靠的或可能是本机编译的SSL库。不过,我不知道为什么在某些情况下有时会在蓝月亮中起作用。

https://github.com/pgjdbc/pgjdbc/blob/f96f6b3c0fdcb9c393b870b834adb1248f955cee/README.md#dependencies

关于java - 为什么PostgreSQL JDBC驱动程序在身份验证期间向服务器发送错误的数据包头?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28466014/

10-10 00:56
查看更多