getInputStream () has already been called for this request แก้ยังไง

เมื่อจำเป็นต้องใช้คำสั่งนี้จาก Class HttpServletRequest เพื่อหาค่า requestBody เช่น getReader , getInputStream และพบ error

java.lang.IllegalStateException: getReader() has already been called for this request
java.lang.IllegalStateException: getInputStream () has already been called for this request

จะแก้อย่างไร ให้เราสร้าง Filter สำหรับทำ CachingRequestBodyFilter

@Component
public class CachingRequestBodyFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest currentRequest = (HttpServletRequest) servletRequest;
        MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(currentRequest);
        chain.doFilter(wrappedRequest, servletResponse);
    }
}

และสร้าง Class MultiReadHttpServletRequest สำหรับเก็บ cache ของ HttpServletRequest ใน class นี้ support servlet 3.0

public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
    private ByteArrayOutputStream cachedBytes;

    public MultiReadHttpServletRequest(HttpServletRequest request) {
        super(request);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (cachedBytes == null)
            cacheInputStream();

        return new CachedServletInputStream();
    }

    @Override
    public BufferedReader getReader() throws IOException{
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    private void cacheInputStream() throws IOException {
    /* Cache the inputstream in order to read it multiple times. For
     * convenience, I use apache.commons IOUtils
     */

        cachedBytes = new ByteArrayOutputStream();
        IOUtils.copy(super.getInputStream(), cachedBytes);
    }

    /* An inputstream which reads the cached request body */
    public class CachedServletInputStream extends ServletInputStream {
        private ByteArrayInputStream input;

        public CachedServletInputStream() {
      /* create a new input stream from the cached request body */
            input = new ByteArrayInputStream(cachedBytes.toByteArray());
        }

        @Override
        public int read() throws IOException {
            return input.read();
        }

        @Override
        public boolean isFinished() {
            return input.available() == 0;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener listener) {
            throw new RuntimeException("Not implemented");
        }
    }
}

หลังจากนั้นเราสามารถเรียกคำสั่งในข้างต้น กี่ครั้งก็ได้ ดังนี้ ยกตัวอย่าง จะหาค่า input ที่เป็นแบบ raw json post string

MultiReadHttpServletRequest multiReadRequest = new MultiReadHttpServletRequest((HttpServletRequest) request);
InputStream inputStream = multiReadRequest.getInputStream();
String rawJsonString = IOUtils.toString(inputStream, "UTF-8");

reference https://stackoverflow.com/questions/47605079/exceptionhandler-how-to-get-raw-json-post-from-httpservletrequest?noredirect=1#comment82190546_47605079

Posted in java, spring boot | Leave a comment

npm private git or bitbucket module

อยากจะสร้าง common lib ไว้ใช้งานโดยผ่าน git หรือ bitbucket ให้ใส่โค้ดไว้ใน package.json มีให้เลือกหลายวิธีดังนี้

Basic auth

GitHub has support for basic auth:

"dependencies" : {
    "my-module" : "git+https://my_username:my_password@github.com/my_github_account/my_repo.git"
}

As does BitBucket:

"dependencies" : {
    "my-module": "git+https://my_username:my_password@bitbucket.org/my_bitbucket_account/my_repo.git"
}

แต่เราไม่ควรใส่ password ลักษณะนี้ใน package.json

Personal access tokens (GitHub) แนะนำ

To make this answer more up-to-date, I would now suggest using a personal access token on GitHub instead of username/password combo.

You should now use:

"dependencies" : {
    "my-module" : "git+https://<username>:<token>@github.com/my_github_account/my_repo.git"
}

For Github you can generate a new token here:

https://github.com/settings/tokens

App passwords (Bitbucket) แนะนำ

App passwords are primarily intended as a way to provide compatibility with apps that don’t support two-factor authentication, and you can use them for this purpose as well. First, create an app password, then specify your dependency like this:

"dependencies" : {
    "my-module": "git+https://<username>:<app-password>@bitbucket.org/my_bitbucket_account/my_repo.git"
}

[Deprecated] API key for teams (Bitbucket)

For BitBucket you can generate an API Key on the Manage Team page and then use this URL:

"dependencies" : {
    "my-module" : "git+https://<teamname>:<api-key>@bitbucket.org/team_name/repo_name.git"
}

reference https://stackoverflow.com/questions/10869796/npm-private-git-module-on-heroku

Posted in nodejs | Leave a comment

MSBUILD : error MSB3428: Could not load the Visual C++ component “VCBuild.exe”

We found the solution, just need run this command as administrator:

npm install --global --production windows-build-tools

Credit https://github.com/nodejs/node-gyp/issues/307#issuecomment-240556824

Posted in node.js, nodejs | Leave a comment

java convert resultset to json

งานลักษณะที่มีการต่อ db ตรงโดยไม่ใช้ JPA query ข้อมูลได้เป็น resultset และจำเป็นต้องแปลงเป็น json เช่น oracle database changed event งานที่ได้รับจำเป็นต้องแปลงข้อมูลที่ได้จาก resultset เป็น json เพื่อไปเก็บบน firebase เราสามารถใช้ method นี้แปลงได้เลย

public JSONArray convertToJSON(ResultSet resultSet) throws Exception {
   JSONArray jsonArray = new JSONArray();
   while (resultSet.next()) {
       int total_rows = resultSet.getMetaData().getColumnCount();
       JSONObject obj = new JSONObject();
       for (int i = 0; i < total_rows; i++) {
          obj.put(resultSet.getMetaData().getColumnLabel(i + 1).toLowerCase(), resultSet.getObject(i + 1));
          jsonArray.put(obj);
       }
   }
   return jsonArray;
}

reference http://biercoff.blogspot.com/2013/11/nice-and-simple-converter-of-java.html

Posted in java | Leave a comment

ตั้งค่า Google’s crawl rate ใน google webmaster tools

หากใครเคยเจอปัญหา โดน google bot ถล่มจนเว็บล่ม เพราะจำนวน index เว็บเราเยอะ โดน google bot ถล่มหน้าเว็บที่มีการเรียก API ที่ซื้อมาและมี limit quota ขอแนะนำวิธีบรรเทาทุกข์ เปลี่ยนแปลงอัตราที่ google เข้ามาไต่เว็บเรา (ไม่มีผลต่ออันดับ)

ให้เข้าไปตั้งค่าที่ google web master tool > site setting > crawl rate > Limit Google’s maximum crawl rate

ยกตัวอย่าง
A Crawl-delay: สมมติตั้งค่าเรท 30 วิ google จะเก็บหน้าเว็บเรา 1,000 หน้า ใช้เวลา 8.3 ชม.

A Crawl-delay: สมมติตั้งค่าเรท 500 วิ (Low Rate) google จะเก็บหน้าเว็บเรา 1,000 หน้า ใช้เวลา 5.8 วัน

หรือจะใช้วิธีใส่ rel=nofollow ใน tag <a> ก็ช่วยได้เช่นกัน แต่ต้องคิดพิจารณา ว่าควรใช้ตรงไหนถึงจะดีที่สุด

Posted in knowledge | Leave a comment