[java] WebView 리소스 요청에 사용자 지정 헤더 추가-Android

WebView에서 오는 모든 요청에 ​​사용자 지정 헤더를 추가해야합니다. 에 loadURL대한 매개 변수가 있다는 것을 알고 extraHeaders있지만 초기 요청에만 적용됩니다. 모든 후속 요청에는 헤더가 포함되지 않습니다. 에서 모든 재정의를 살펴 보았지만 WebViewClient리소스 요청에 헤더를 추가 할 수있는 것은 없습니다 onLoadResource(WebView view, String url). 어떤 도움이라도 좋을 것입니다.

고마워, 레이



답변

시험

loadUrl(String url, Map<String, String> extraHeaders)

리소스로드 요청에 헤더를 추가하려면 사용자 지정 WebViewClient를 만들고 다음을 재정의합니다.

API 24+:
WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request)
or
WebResourceResponse shouldInterceptRequest(WebView view, String url)


답변

WebViewClient.shouldInterceptRequest를 사용하여 각 요청을 가로 채야합니다.

인터 셉션 할 때마다 URL을 가져 와서 직접 요청한 다음 콘텐츠 스트림을 반환해야합니다.

WebViewClient wvc = new WebViewClient() {
    @Override
    public WebResourceResponse shouldInterceptRequest(WebView view, String url) {

        try {
            DefaultHttpClient client = new DefaultHttpClient();
            HttpGet httpGet = new HttpGet(url);
            httpGet.setHeader("MY-CUSTOM-HEADER", "header value");
            httpGet.setHeader(HttpHeaders.USER_AGENT, "custom user-agent");
            HttpResponse httpReponse = client.execute(httpGet);

            Header contentType = httpReponse.getEntity().getContentType();
            Header encoding = httpReponse.getEntity().getContentEncoding();
            InputStream responseInputStream = httpReponse.getEntity().getContent();

            String contentTypeValue = null;
            String encodingValue = null;
            if (contentType != null) {
                contentTypeValue = contentType.getValue();
            }
            if (encoding != null) {
                encodingValue = encoding.getValue();
            }
            return new WebResourceResponse(contentTypeValue, encodingValue, responseInputStream);
        } catch (ClientProtocolException e) {
            //return null to tell WebView we failed to fetch it WebView should try again.
            return null;
        } catch (IOException e) {
             //return null to tell WebView we failed to fetch it WebView should try again.
            return null;
        }
    }
}

Webview wv = new WebView(this);
wv.setWebViewClient(wvc);

최소 API 대상이 레벨 21 인 경우 URL 대신 추가 요청 정보 (예 : 헤더)를 제공 하는 새로운 shouldInterceptRequest 를 사용할 수 있습니다 .


답변

어쩌면 내 대답은 아주 늦게, 그러나 그것은 API를 커버 아래위의 21 수준.

헤더를 추가하려면 모든 요청을 가로 채서 필요한 헤더로 요청만들어야 합니다.

따라서 두 경우 모두에서 호출되는 shouldInterceptRequest 메서드 를 재정의해야합니다 . 1. 레벨 21까지의 API; 2. API 레벨 21 이상

    webView.setWebViewClient(new WebViewClient() {

        // Handle API until level 21
        @SuppressWarnings("deprecation")
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {

            return getNewResponse(url);
        }

        // Handle API 21+
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {

            String url = request.getUrl().toString();

            return getNewResponse(url);
        }

        private WebResourceResponse getNewResponse(String url) {

            try {
                OkHttpClient httpClient = new OkHttpClient();

                Request request = new Request.Builder()
                        .url(url.trim())
                        .addHeader("Authorization", "YOU_AUTH_KEY") // Example header
                        .addHeader("api-key", "YOUR_API_KEY") // Example header
                        .build();

                Response response = httpClient.newCall(request).execute();

                return new WebResourceResponse(
                        null,
                        response.header("content-encoding", "utf-8"),
                        response.body().byteStream()
                );

            } catch (Exception e) {
                return null;
            }

        }
   });

응답 유형을 처리해야하는 경우 변경할 수 있습니다.

        return new WebResourceResponse(
                null, // <- Change here
                response.header("content-encoding", "utf-8"),
                response.body().byteStream()
        );

        return new WebResourceResponse(
                getMimeType(url), // <- Change here
                response.header("content-encoding", "utf-8"),
                response.body().byteStream()
        );

및 추가 방법

        private String getMimeType(String url) {
            String type = null;
            String extension = MimeTypeMap.getFileExtensionFromUrl(url);

            if (extension != null) {

                switch (extension) {
                    case "js":
                        return "text/javascript";
                    case "woff":
                        return "application/font-woff";
                    case "woff2":
                        return "application/font-woff2";
                    case "ttf":
                        return "application/x-font-ttf";
                    case "eot":
                        return "application/vnd.ms-fontobject";
                    case "svg":
                        return "image/svg+xml";
                }

                type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
            }

            return type;
        }


답변

앞에서 언급했듯이 다음을 수행 할 수 있습니다.

 WebView  host = (WebView)this.findViewById(R.id.webView);
 String url = "<yoururladdress>";

 Map <String, String> extraHeaders = new HashMap<String, String>();
 extraHeaders.put("Authorization","Bearer"); 
 host.loadUrl(url,extraHeaders);

나는 헤더를 검사하기 위해 Authorize Attribute를 확장 한 MVC 컨트롤러로 이것을 테스트했고 헤더가 거기에 있습니다.


답변

이것은 나를 위해 작동합니다.

  1. 먼저 요청에 추가하려는 헤더를 반환하는 메서드를 만들어야합니다.

    private Map<String, String> getCustomHeaders()
    {
        Map<String, String> headers = new HashMap<>();
        headers.put("YOURHEADER", "VALUE");
        return headers;
    }
    
  2. 두 번째로 WebViewClient를 만들어야합니다.

    private WebViewClient getWebViewClient()
    {
    
        return new WebViewClient()
        {
    
        @Override
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request)
        {
            view.loadUrl(request.getUrl().toString(), getCustomHeaders());
            return true;
        }
    
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url)
        {
            view.loadUrl(url, getCustomHeaders());
            return true;
        }
    };
    }
    
  3. WebViewClient를 WebView에 추가합니다.

    webView.setWebViewClient(getWebViewClient());

도움이 되었기를 바랍니다.


답변

loadUrl을 건너 뛰고 Java의 HttpURLConnection을 사용하여 자체 loadPage를 작성하여 모든 헤더를 제어 할 수 있어야합니다. 그런 다음 webview의 loadData를 사용하여 응답을 표시합니다.

Google이 제공하는 헤더에 대한 액세스 권한이 없습니다. WebView 소스의 깊은 곳에서 JNI 호출에 있습니다.


답변

다음은 HttpUrlConnection을 사용한 구현입니다.

class CustomWebviewClient : WebViewClient() {
    private val charsetPattern = Pattern.compile(".*?charset=(.*?)(;.*)?$")

    override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? {
        try {
            val connection: HttpURLConnection = URL(request.url.toString()).openConnection() as HttpURLConnection
            connection.requestMethod = request.method
            for ((key, value) in request.requestHeaders) {
                connection.addRequestProperty(key, value)
            }

            connection.addRequestProperty("custom header key", "custom header value")

            var contentType: String? = connection.contentType
            var charset: String? = null
            if (contentType != null) {
                // some content types may include charset => strip; e. g. "application/json; charset=utf-8"
                val contentTypeTokenizer = StringTokenizer(contentType, ";")
                val tokenizedContentType = contentTypeTokenizer.nextToken()

                var capturedCharset: String? = connection.contentEncoding
                if (capturedCharset == null) {
                    val charsetMatcher = charsetPattern.matcher(contentType)
                    if (charsetMatcher.find() && charsetMatcher.groupCount() > 0) {
                        capturedCharset = charsetMatcher.group(1)
                    }
                }
                if (capturedCharset != null && !capturedCharset.isEmpty()) {
                    charset = capturedCharset
                }

                contentType = tokenizedContentType
            }

            val status = connection.responseCode
            var inputStream = if (status == HttpURLConnection.HTTP_OK) {
                connection.inputStream
            } else {
                // error stream can sometimes be null even if status is different from HTTP_OK
                // (e. g. in case of 404)
                connection.errorStream ?: connection.inputStream
            }
            val headers = connection.headerFields
            val contentEncodings = headers.get("Content-Encoding")
            if (contentEncodings != null) {
                for (header in contentEncodings) {
                    if (header.equals("gzip", true)) {
                        inputStream = GZIPInputStream(inputStream)
                        break
                    }
                }
            }
            return WebResourceResponse(contentType, charset, status, connection.responseMessage, convertConnectionResponseToSingleValueMap(connection.headerFields), inputStream)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return super.shouldInterceptRequest(view, request)
    }

    private fun convertConnectionResponseToSingleValueMap(headerFields: Map<String, List<String>>): Map<String, String> {
        val headers = HashMap<String, String>()
        for ((key, value) in headerFields) {
            when {
                value.size == 1 -> headers[key] = value[0]
                value.isEmpty() -> headers[key] = ""
                else -> {
                    val builder = StringBuilder(value[0])
                    val separator = "; "
                    for (i in 1 until value.size) {
                        builder.append(separator)
                        builder.append(value[i])
                    }
                    headers[key] = builder.toString()
                }
            }
        }
        return headers
    }
}

WebResourceRequest는 POST 데이터를 제공하지 않기 때문에 POST 요청에는 작동하지 않습니다. POST 데이터를 가로 채기 위해 JavaScript 주입 해결 방법을 사용 하는 Request Data-WebViewClient 라이브러리 가 있습니다.