Важное примечание. Был прорыв в Edit # 2 в конце, поэтому обязательно прочтите это.Почему драйвер PostgreSQL JDBC отправляет плохой заголовок пакета на сервер во время аутентификации?
Я в clojure, пытаясь использовать 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"])
Когда я запускаю этот код, я получаю один из трех результатов:
- орга. postgresql.util.PSQLException: попытка подключения не удалась.
- org.postgresql.util.PSQLException: ОШИБКА: плохой заголовок пакета: '70'
- ОЧЕНЬ РАВНО (три раза сейчас, из сотен попыток), это действительно сработает! Она возвращает
({:?column? 5})
Что происходит? Почему эта работа иногда, но почти NEVER?
Мои настройки
- OS X Yosemite (но я никогда не мог заставить его работать с моей виртуальной машине Ubuntu, либо.)
lein repl :headless :port 2358
с последующимcider-connect
в Emacs.- Сервер Postgres 9.1.12
Edit # 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 с заголовком «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 разрушает мою жизнь снова? Я думал, что мы оставили эти плохие дни позади нас так давно.
Так что теперь мне интересно, есть ли способ изменить клиентскую кодировку. Или, возможно, изменить используемый метод аутентификации.
Это может быть также полезно знать, что программа PSQL клиент работает без сучка от моей машины. Это заставляет меня думать, что это какая-то странность jdbc, а не проблема с сетью. –
Я просто попытался сделать это с чистой Java (т. Е. Не в Clojure.) Я получаю те же результаты. Удивительно, что pgBouncer не играет хорошо с JDBC. –