解决无法使用AJAX传GB2312中文,只能Utf-8的编码问题。

本文介绍如何解决在使用AJAX时只能发送UTF-8编码,无法发送GB2312编码的中文字符的问题。通过JS手动转码和重写jQuery AJAX方法,实现了GB2312编码的传输,避免了乱码。文中还探讨了URL编码、Unicode与UTF-8的区别,并提供了相关代码示例。

暴力解决AJAX传GB2312编码的字符串

通过js暴力转码,解决项目中ajax只能utf-8的问题,ajax的req只Content-Type : xxxx;charset=UTF-8。爷无语,不管怎么改xhr.setRequestHeader(“Content-Type”,“application/x-www-form-urlencoded;charset=gb2312”),都不给点反应的。

解决方法

整个项目是GB2312编码,后端是c语言,arm 。整个结构大概就是后台管理,前台用户。管理账号少,用的也就是前后不分离的操作非常省事,完全的也七七八八,完美。

但是前台用户量多,请求可能会比较大,准备分离,但是jq也好原生ajax也好,怎么整都是utf-8,成片的乱码。也用了挺多方法,最后找了一个js手动转码的方法。

如果想用上jq的话,本篇最后也提供了想法,大概就是找jq的封装方法,把转编码重写,见下面jq段落。

上连接:https://gitee.com/leaflxd/encodeToGb2312?_from=gitee_search

转码js:

function(){
	var json = {...
	}
	// 自己进连接看
	var encodeToGb2312 = function(str)
    {
    	if(typeof(str) === "number")
        {
            return str;
        }
        else
        {
	        var strOut="";
	        for(var i = 0; i < str.length; i++)
	        {
	            strOut += "%";
	            var c = str.charAt(i); 
	            var code = str.charCodeAt(i);
	            var gcode = json[code.toString(16).toUpperCase()];
	            if(gcode && gcode.length % 2 !== 0) 
	            {
	                gcode = "0" + gcode;
	            }
	            if(c==" ") 
	            {
	                strOut += "20";
	            }
	            else if(code < 164)
	            {
	                var b = str.charCodeAt(i).toString(16);
	                if(b && b.length % 2 !== 0) b = "0" + b;
	                strOut += b;
	            }
	            else if(gcode)
	            {
	                strOut += gcode[0]+gcode[1]+"%"+gcode[2]+gcode[3];
	            } 
	            else
	            {
	            	//异常直接打印中文一一一,总得打印点什么233
	            	//unicode 4e00 ; gb2312 d2bb 
	                strOut += "D2%BB";
	            }
        	}
        }
	}
}

xhr js:

document.getElementById("btn2").onclick = function()
{
    //alert("a");
    type = "POST"
    url = "/main/TestCgic";
    conttype = "application/x-www-form-urlencoded;charset=gb2312";

    v = document.getElementById("t1").value;

    data = "pass="+encodeToGb2312(v);
    console.log(data);
    reqcgic(type, url, conttype, data, 
    function showdata(value){
        document.getElementById("p2").innerText = value;
    });
}

......

function reqcgic(type, url, conttype, data, callback)
{
	xhr = createXHR();
	
	xhr.open(type, url, true);
	xhr.setRequestHeader("Content-Type",conttype);
	xhr.onreadystatechange = function()
	{
		if(xhr.readyState == 4 && (xhr.status == 200 || xhr.status == 304) )
		{
			console.log(xhr);
			callback(xhr.responseText);
		}
	};
	xhr.send(data);
}

大概就是这个意思
实际效果:
效果图头部:
请求头部
请求体:
请求体

其他方法

其他方法也看了蛮多
就说一下最多的是方法,两种本质是一样的,一个是js一个是jq

js

  • 两个函数先写上
    escape
    unescape
    encodeURIComponent
    decodeURIComponent
    大体意思是转解码,上面两unicode,下面两utf-8,可以自行尝试下。
    decodeURIComponent有一个报错单独拎出来一下,URIError: malformed URI sequence,转义造成的问题。上连接https://blog.csdn.net/chuangxin/article/details/84242109
  • 前端:
    前面js处使用escape变成Uincode编码,然后套一个encodeURIComponent。
    escape是转成Uincode的编码,格式%uxxxx,这里encodeURIComponent这个大概意思就是再转utf-8,也就是我们变成我们请求体里面的东西了,如上图那样。但是因为是%uxxxx,所以请求体里是%25uxxxx,后面接受到的字符串是%uxxxx。见图
    在这里插入图片描述
    在这里插入图片描述
    这里有两种处理方法,一种直接传到前端,然后unescape显示回来,另一种就是后面处理,将unicode转成GB2312。一般来说第二种,因为有些也不单单是只有网页的,所以编码统一很重要,主要还是看项目。
    c语言的转码是#include <iconv.h>,但是我没成功,还是对js下的手。代码如下,上连接https://blog.csdn.net/violet089/article/details/51568667

iconv c

/********************************************************************************************************
** 函数名称:	code_convert()
** 函数主题:	u转gb2312
** 功能描述:	
********************************************************************************************************/
int code_convert(char *inbuf,char *outbuf)
{
    iconv_t cd;
    int rc;
    char **pin = &inbuf;
    char **pout = &outbuf;
	
    int inlen   = strlen(inbuf);
    int outlen  = strlen(outbuf);
	
    cd = iconv_open("GB2312","UNICODE//IGNORE");
    if(cd == -1)
	{
		printf("<cd:%d>", cd);
	}
	/* 
	* cd 全是-1,iconv_open里面有各种说法
	* 我尝试了GB2312,UNICODE//IGNORE,UTF-8,UNICODELITTLE,全是-1,一0难见啊
	* 还有可能是库相关版本造成的
	* 更新iconv相关函数有两种方法:
	* 第一,更新libc库;
	* 第二,更新libiconv库;
	* 这个么环境原因就不尝试了,相关连接:https://blog.csdn.net/violet089/article/details/51568667
	*/
	return 0;
    memset(outbuf,0,outlen);
	
    iconv(cd,pin,&inlen,pout,&outlen);
	printf("<0:%s:%s>", inbuf, outbuf);
    iconv_close(cd);
    return 0;
}

jq

见 jquery-1.11.0.js 第9505行。

jQuery.param = function( a, traditional ) {
	var prefix,
		s = [],
		add = function( key, value ) {
			// If value is a function, invoke it and return its value
			value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
			s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
		};

	............
	.......
	...
};

疑问

上面jq方法我也就有个疑问,为什么encodeURIComponent用了之后就能正常发呢,正常来说,在没有上面所有操作下,一个中文传到了后面,打印出来就是9个字符,然后变成GB2312中文就是四个乱码+一个?,说明可能还有一次utf-8转码。为什么转码之后就没事了,%为什么不会变成%25。迷惑,俺也不晓得。

jq版解决方法

已经重写完了,直接上代码了

jqOverride.js


//重写jq.param
function buildParams( prefix, obj, traditional, add ) {
	var name;

	if ( jQuery.isArray( obj ) ) {
		// Serialize array item.
		jQuery.each( obj, function( i, v ) {
			if ( traditional || rbracket.test( prefix ) ) {
				// Treat each array item as a scalar.
				add( prefix, v );

			} else {
				// Item is non-scalar (array or object), encode its numeric index.
				buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
			}
		});

	} else if ( !traditional && jQuery.type( obj ) === "object" ) {
		// Serialize object item.
		for ( name in obj ) {
			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
		}

	} else {
		// Serialize scalar item.
		add( prefix, obj );
	}
}

$.param = function( a, traditional ) {
	var prefix,
		s = [],
		add = function( key, value ) {
			// If value is a function, invoke it and return its value
			value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
			s[ s.length ] = encodeToGb2312( key ) + "=" + encodeToGb2312( value );
		};

	// Set traditional to true for jQuery <= 1.3.2 behavior.
	if ( traditional === undefined ) {
		traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
	}

	// If an array was passed in, assume that it is an array of form elements.
	if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
		// Serialize the form elements
		jQuery.each( a, function() {
			add( this.name, this.value );
		});

	} else {
		// If traditional, encode the "old" way (the way 1.3.2 or older
		// did it), otherwise encode params recursively.
		for ( prefix in a ) {
			buildParams( prefix, a[ prefix ], traditional, add );
		}
	}

	// Return the resulting serialization
	return s.join( "&" ).replace( /%20/g, "+" );
};


https://www.cnblogs.com/liushui-sky/p/10483248.html

关于URL编码

如上述连接中所述,中文在转成URL编码是三个字符串,通过unicode进行转换。
原文:

8、注意unicode的字符编码和utf-8的存储编码表示是不同的,例如"严"字的Unicode码是4E25,UTF-8编码是E4B8A5,这个7里面解释了的,UTF-8编码不仅考虑了编码,还考虑了存储,E4B8A5是在存储识别编码的基础上塞进了4E25。

4E25的二进制位 0100,1110,0010,0101 中文汉字在utf-8中到底占几个字节,一般是3个字节(原因见第一章),最常见的编码方式是1110xxxx 10xxxxxx 10xxxxxx。组合起来为 1110,0100,1011,1000,1010,0101 =E4B8A5

其中

  • application/x-www-form-urlencoded:需要编码

  • multipart/form-data:并不需要

因为URL编码解决的是单字节和多字节在http传输中冲突而产生的

当我们需要发送一个多字节字符,例如中文的中字,如果直接使用utf-8编码发送,其编码为0xE4B8AD,会使用三个字节传输,分别为0xE4,0xB8,0xAD,当某些中文或者多字节的字符发送时,恰好有一个字节解码为0x26或者0x3D时,这个多字节字符中一个字节将会被接收段解码为=或&符号这中特殊字节,从而将数据从此处断开,产生数据的错误。原文连接https://www.cnblogs.com/k5210202/p/13819449.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值