需求很簡單,希望餵個標題跟內容,就自動產生文章貼到 Blogger 上,但弄的跌跌撞撞的,紀錄一下,留給麵包屑給未來的自己和有需要的人。
先來看一下官方作法 - 新增 Post 的做法,可以透過 Restful Web API 或是官方提供的 Java Library 來完成。理想上是這樣,看起來很間單,那為什麼我會跌的狗吃屎?
Restful Web API 的方式,參考指南這一篇,才發現 HTTP Header 還要填入 Authorization: /* OAuth 2.0 token here */,基本上就還是要透過 OAuth 2.0 的方式得到 token 才走的下去。那換成官方提供的 Java Library,反正連 Sample Code 都有了應該很簡單,貼上去才發現範例中的 OAuth2Native 根本沒有,需要自己實作。
做到這邊我心已死,成功之路沒有捷徑,只好去翻這兩份文件來看:
- Using OAuth 2.0 with the Google API Client Library for Java
- OAuth 2.0 and the Google OAuth Client Library for Java
- 到 https://console.developers.google.com/ 下的 API 和驗證>API 把 Blogger API 啟用。
- 到 https://console.developers.google.com/ 下的 API 和驗證>同意畫面 把該填的資訊填一填。
- 到 https://console.developers.google.com/ 下的 API 和驗證>憑證>OAuth 建立用戶端 ID,類型選取已安裝的應用程式(我的 APP 是一個桌面執行程式)。
- 此時會得到用戶端 ID,用戶端密碼。
- 修改官方範例碼如下:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// The BlogId of a test blog. | |
String TEST_BLOG_ID = "8070105920543249955"; | |
// Configure the Java API Client for Installed Native App | |
HttpTransport HTTP_TRANSPORT = new NetHttpTransport(); | |
JsonFactory JSON_FACTORY = new JacksonFactory(); | |
// set up authorization code flow | |
AuthorizationCodeFlow flow = new AuthorizationCodeFlow.Builder( | |
BearerToken.authorizationHeaderAccessMethod(), | |
HTTP_TRANSPORT, | |
JSON_FACTORY, | |
new GenericUrl("https://accounts.google.com/o/oauth2/token"), | |
new ClientParametersAuthentication("用戶端ID", "用戶端密碼"), | |
"用戶端ID", | |
"https://accounts.google.com/o/oauth2/auth") | |
.setScopes(Arrays.asList(BloggerScopes.BLOGGER)) | |
.setDataStoreFactory(MemoryDataStoreFactory.getDefaultInstance()) | |
.build(); | |
// authorize | |
LocalServerReceiver receiver = new LocalServerReceiver.Builder() | |
.setHost("127.0.0.1") | |
.setPort(8080).build(); | |
Credential credential = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user"); | |
// Construct the Blogger API access facade object. | |
Blogger blogger = Blogger.builder(HTTP_TRANSPORT, JSON_FACTORY) | |
.setApplicationName("Blogger-PostsInsert-Snippet/1.0") | |
.setHttpRequestInitializer(credential).build(); | |
// Construct a post to insert | |
Post content = new Post(); | |
content.setTitle("A test post"); | |
content.setContent("With HTML content"); | |
// The request action. | |
Insert postsInsertAction = blogger.posts().insert(TEST_BLOG_ID, content); | |
// Restrict the result content to just the data we need. | |
postsInsertAction.setFields("author/displayName,content,published,title,url"); | |
// This step sends the request to the server. | |
Post post = postsInsertAction.execute(); | |
// Now we can navigate the response. | |
System.out.println("Title: " + post.getTitle()); | |
System.out.println("Author: " + post.getAuthor().getDisplayName()); | |
System.out.println("Published: " + post.getPublished()); | |
System.out.println("URL: " + post.getUrl()); | |
System.out.println("Content: " + post.getContent()); |
但實際上這段程式碼還是需要人為介入(在瀏覽器上同意),其實在 https://console.developers.google.com/ 下的 API 和驗證>憑證>OAuth 建立用戶端 ID,有一個類型叫做服務帳戶(Service Account)可以自動通過 OAuth 認證,但因為 Blogger 平台不支援用服務帳戶來發文,所以我們會得到 HTTP 403 授權失敗的錯誤。
PS: Google 關於通過 OAuth 的範例程式碼